init
|
|
@ -0,0 +1,7 @@
|
|||
JWT_SECRET=
|
||||
RCC_HOST=
|
||||
logshook=
|
||||
PROD=true
|
||||
LOCALCERTIFICATEPATH=
|
||||
LOCALREDISCONNECTION=
|
||||
DB_PASSWORD=
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
node_modules/
|
||||
assets/release.zip
|
||||
assets/hash.txt
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQC04Nimx5hGYvQ54rZPWJ9qvvoPSsBXt3PREKhramu1gXpv+W4Mh/vdzlTsNqmedZ2gaX0rd9smy3Kp2lgxKsuyX1gc918k9L/PUzKvnfxy93RDwXdo6qJze+mdQlkDi9U5W4MAzcx6ann3YTHyiKHfs9DqF+kBJQiloPgcnk3HPQIDAQABAoGBAJsAR4h8aGiA6esk9bf/KPWP3Lf4BeXlRrF0xe7uzohHAYYtSHoimdqUsz+NBEPPZJmPbH0wg7O2Cne1rXfMxaqPoZAl/N5kN0uFFY6U7FS+rssF0/OXZPuehmBkOscVGGNM6glAzOfW2/3rZcm8Z3XhdhTQIzZq2D1rjhKU3YT9AkEA08e3BTsV3iqjf8kJhwdt7EGX9/QutNaUSkAoW1d/pRdjZbbfcFwLri2WcTA2taoIa892hSTz/qaHYWMfu3oy/wJBANqlVeqRxFX8YJ0yFZfblx/QEkA5ospJI5pd3J6kSqK9A3NqBCbFPxH6NO8rXBSHk8cE2vNVc0K7qSCzn6sqEcMCQCCHIlNJWfh/sBEmfbIhr/6DrKXG+Y2JD8m/xPMSo2ZmCzxKNFN7r8eW9O55q02HyjdU7C1TGa7ZQR3yLaOMB10CQAY3Iv0bDbDADuMJFHIPrPkbihlHSihj8d4mguoDk5eStfFm9x0/CC7zpOOToPd4byv+KFc4e6FPAlzKnmRYOs8CQQCDMYYdcIw5e5nf20yLUhwzJL4q8ZyR7OGXkjz6ACxoxQSncr/adjecz21ngdx3nq13RdpppWNuZ/2exvS3ObTG
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEowIBAAKCAQEApH8yULE5/DRBnSTqcOM3PplW2UGD4povfR8zCBNP1n69uKoG
|
||||
mcJm4AiPAR18TpLXPNAyp8UwlrQc4+GCqU/ktipFp//W6r90BWyiY69flfTGU8Zs
|
||||
Bcy2DNjQipilSaJoOjxUbT++D7qrQSCiMh6fzUfEcUyk2kx4ICErQ2/HqHOxHbLi
|
||||
+R7L/bIU9pZYWB6aU0WM7ATuzDYFVETUSlXpMAVKeusEqae8lEfV5TqZxb3eIUPU
|
||||
P1iz7eqd7jQH6UygOnjFksSYxOInbr4KK2rQYDt6507ohO/+AzhlH+FPM3/ziqN6
|
||||
LObRkLF4u4HCUaKZqPQTREIz8zYdNXuY43YeEQIDAQABAoIBABdUjv9Q04eIpdGy
|
||||
3albIIe5Wc8AcsMd2SRm22cGzij+2supGbyPDOYzcIzY8Lt4KhzO7pBK8GQ/cWWE
|
||||
o3J+CVMo1a5JI+MxejQWv0ViJy1uhP52wvVjnmJeEd3GXpL9/MhdrB++jadPc2CO
|
||||
T1LKcyG7Two+s5beh58O9ULgRLIIU0m6n+svCIDHY0VlxuAh/i5axqk/aaCzvtAh
|
||||
DeFNS6vrBRMhAY8Tzlhlm/SXEiIubHjrO+CYhLLe0hh0AmaLQNQ0JLFW/eJwMWxw
|
||||
qEoT+tL1cMYZCudjfmffILXLxYWfd5HqOWz/ghFiSayAdKJZr1gcA3ZAQQVS5qUW
|
||||
6VDRvF0CgYEA+LBOBLMWyG57PZAI2n85h4PDZKgn6hzJMVlXGelMiRhI/mNcCL/M
|
||||
Ay006mZ22QyR0Fm59OTHeWxyz8AtCSrSn6rLi4fiLYlh3xxTN1O8Q4Rf7HqNgvTf
|
||||
rgpjGJ8fIHTvzqQesclKN+MXhsaw3NpS/MyzGEc7ORTTtzqwRDHYKWcCgYEAqVU+
|
||||
C087RxG8v2ruNeIf+fxnDkrpeHeklfWzCVTNo18FnQhvmFkW0SpfjwhAhjfEEOHZ
|
||||
VfsDp/kmXZTynkce1DTfWv8iAac990bgBVx6/rC4VoAYQ18jg72FcICGYX4rv9bo
|
||||
gHi87rPJ1qsVVW2poJyYWr5ZpxIqNtQcQ8NaOccCgYBcS/q4rcrf2nks0P8oMJ2m
|
||||
WNW0zt/5eHOHODQmbrq0CupUV4X5zU0nRKjl8d9cENkxLYvhguMxgnld92H/jAAd
|
||||
uCLRBz5/TgSf7IBKAW7W1BNRze4lU0KM8lfy9GN2BVBXLfwiWaWM9mBt6eIMJY81
|
||||
ObeiZBVryvoEf+iZdrJWMwKBgQCAPkDJC+6W+oX6ap+SS3lwOIpMNsvvIp2RvQ0l
|
||||
CgbbrgFwVo090msHapIIn3VOsTlal9Gj3oF8W6OEyGOfH7nneUuXfRZiLikt941+
|
||||
QfYcofZZ/JVjoNAi3AwNkikz+PxlQ/u+ILLmDV/Vpqh3lKAdNbvlLbh0Ybt63tWx
|
||||
NGhGzQKBgC2gnP65oBbORgdCkMvrs+fbBX5LdCTrBUkxX4yVMr/25GS1oqX6LiGK
|
||||
Oxjs326pGGns91cMEUbxSFQwaWPCcTWhEbK/epdlY3NkFQ4WPDPkEmhhp49ebMA7
|
||||
BYWSO7nSEMv4S6rRnVxts9lCihNclblbg3erXx77PRKnLtVbE+KG
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# SushiBlox-Website
|
||||
Website for sushiblox I guess.
|
||||
|
||||
Private for now might open source.
|
||||
|
||||
The setup is easy install required node modules and setup a nginx reverse proxy on port 9000.
|
||||
|
||||
Uses MongoDB for datastorage. Redis for special things
|
||||
|
||||
# Advice
|
||||
This uses hardcoded domain names in the code and relies on cloudflare headers for IP configs. so yeahhhhhhhhhhhhhhhhhhhhhhhhhh
|
||||
|
||||
|
||||
# Redis
|
||||
idk set it up nerd
|
||||
|
||||
# setup
|
||||
LOL I DID NOT MAKE THIS EASY
|
||||
|
||||
# Example
|
||||
|
||||
```
|
||||
PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host pm2 start server.mjs
|
||||
```
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
local url = "http://mete0r.xyz" -- have to set to https for production
|
||||
------------------- UTILITY FUNCTIONS --------------------------
|
||||
|
||||
|
||||
|
||||
function waitForChild(parent, childName)
|
||||
while true do
|
||||
local child = parent:findFirstChild(childName)
|
||||
if child then
|
||||
return child
|
||||
end
|
||||
parent.ChildAdded:wait()
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------END UTILITY FUNCTIONS -------------------------
|
||||
|
||||
-----------------------------------"CUSTOM" SHARED CODE----------------------------------
|
||||
--print(port)
|
||||
pcall(function() settings().Network.UseInstancePacketCache = true end)
|
||||
pcall(function() settings().Network.UsePhysicsPacketCache = true end)
|
||||
--pcall(function() settings()["Task Scheduler"].PriorityMethod = Enum.PriorityMethod.FIFO end)
|
||||
pcall(function() settings()["Task Scheduler"].PriorityMethod = Enum.PriorityMethod.AccumulatedError end)
|
||||
|
||||
--settings().Network.PhysicsSend = 1 -- 1==RoundRobin
|
||||
--settings().Network.PhysicsSend = Enum.PhysicsSendMethod.ErrorComputation2
|
||||
settings().Network.PhysicsSend = Enum.PhysicsSendMethod.TopNErrors
|
||||
settings().Network.ExperimentalPhysicsEnabled = true
|
||||
settings().Network.WaitingForCharacterLogRate = 100
|
||||
pcall(function() settings().Diagnostics:LegacyScriptMode() end)
|
||||
|
||||
-----------------------------------START GAME SHARED SCRIPT------------------------------
|
||||
|
||||
local assetId = placeId -- might be able to remove this now
|
||||
|
||||
local scriptContext = game:GetService('ScriptContext')
|
||||
pcall(function() scriptContext:AddStarterScript(37801172) end)
|
||||
scriptContext.ScriptsDisabled = true
|
||||
|
||||
game:SetPlaceID(assetId, false)
|
||||
game:GetService("ChangeHistoryService"):SetEnabled(false)
|
||||
|
||||
-- establish this peer as the Server
|
||||
local ns = game:GetService("NetworkServer")
|
||||
|
||||
if url~=nil then
|
||||
pcall(function() game:GetService("Players"):SetAbuseReportUrl(url .. "/AbuseReport/InGameChatHandler.ashx") end)
|
||||
---@diagnostic disable-next-line: invalid-class-name
|
||||
pcall(function() game:GetService("ScriptInformationProvider"):SetAssetUrl(url .. "/Asset/") end)
|
||||
pcall(function() game:GetService("ContentProvider"):SetBaseUrl(url .. "/") end)
|
||||
--pcall(function() game:GetService("Players"):SetChatFilterUrl(url .. "/Game/ChatFilter.ashx") end)
|
||||
|
||||
game:GetService("BadgeService"):SetPlaceId(placeId)
|
||||
|
||||
game:GetService("BadgeService"):SetIsBadgeLegalUrl("")
|
||||
game:GetService("InsertService"):SetBaseSetsUrl(url .. "/Game/Tools/InsertAsset.ashx?nsets=10&type=base")
|
||||
game:GetService("InsertService"):SetUserSetsUrl(url .. "/Game/Tools/InsertAsset.ashx?nsets=20&type=user&userid=%d")
|
||||
game:GetService("InsertService"):SetCollectionUrl(url .. "/Game/Tools/InsertAsset.ashx?sid=%d")
|
||||
game:GetService("InsertService"):SetAssetUrl(url .. "/Asset/?id=%d")
|
||||
game:GetService("InsertService"):SetAssetVersionUrl(url .. "/Asset/?assetversionid=%d")
|
||||
|
||||
pcall(function() loadfile(url .. "/Game/LoadPlaceInfo.ashx?PlaceId=" .. placeId)() end)
|
||||
|
||||
-- pcall(function()
|
||||
-- if access then
|
||||
-- loadfile(url .. "/Game/PlaceSpecificScript.ashx?PlaceId=" .. placeId .. "&" .. access)()
|
||||
-- end
|
||||
-- end)
|
||||
end
|
||||
pcall(function() game:GetService("NetworkServer"):SetIsPlayerAuthenticationRequired(true) end)
|
||||
settings().Diagnostics.LuaRamLimit = 0
|
||||
--settings().Network:SetThroughputSensitivity(0.08, 0.01)
|
||||
--settings().Network.SendRate = 35
|
||||
--settings().Network.PhysicsSend = 0 -- 1==RoundRobin
|
||||
|
||||
if placeId~=nil and url~=nil then
|
||||
-- yield so that file load happens in the heartbeat thread
|
||||
wait()
|
||||
|
||||
-- load the game
|
||||
game:Load(url .. "/asset?id=" .. placeId .. "&method=rcc")
|
||||
end
|
||||
|
||||
-- Now start the connection
|
||||
|
||||
local success, message = pcall(function() ns:Start(port) end)
|
||||
if not success then
|
||||
local HttpService = game:GetService("HttpService")
|
||||
game:GetService("HttpService").HttpEnabled = true
|
||||
-- failed job close it
|
||||
local arguments = {
|
||||
["game"] = placeId
|
||||
}
|
||||
HttpService:PostAsync(
|
||||
url .. "/api/updategameinfo/closejob",
|
||||
HttpService:JSONEncode(arguments)
|
||||
)
|
||||
else
|
||||
local HttpService = game:GetService("HttpService")
|
||||
local arguments = {
|
||||
["game"] = placeId
|
||||
}
|
||||
game:HttpPostAsync(url .. "/api/updategameinfo/gameloaded",HttpService:JSONEncode(arguments),"application/json")
|
||||
end
|
||||
|
||||
scriptContext:SetTimeout(10)
|
||||
scriptContext.ScriptsDisabled = false
|
||||
|
||||
|
||||
------------------------------END START GAME SHARED SCRIPT--------------------------
|
||||
|
||||
|
||||
|
||||
-- StartGame --
|
||||
game:GetService("RunService"):Run()
|
||||
|
||||
|
||||
local HttpService = game:GetService("HttpService")
|
||||
game:GetService("HttpService").HttpEnabled = true
|
||||
|
||||
spawn(function()
|
||||
-- if a player doesn't join in 60 seconds because of failed job or they didn't join close the job
|
||||
wait(60)
|
||||
if #game:GetService("Players"):GetPlayers() < 1 then
|
||||
print("Shutdown time")
|
||||
-- less than one player is in the game so lets shut down
|
||||
local arguments = {
|
||||
["game"] = placeId
|
||||
}
|
||||
HttpService:PostAsync(
|
||||
url .. "/api/updategameinfo/closejob",
|
||||
HttpService:JSONEncode(arguments)
|
||||
)
|
||||
end
|
||||
end)
|
||||
|
||||
local function addAttachment(part, name, position, orientation)
|
||||
local attachment = Instance.new("Attachment")
|
||||
attachment.Name = name
|
||||
attachment.Parent = part
|
||||
if position then
|
||||
attachment.Position = position
|
||||
end
|
||||
if orientation then
|
||||
attachment.Orientation = orientation
|
||||
end
|
||||
return attachment
|
||||
end
|
||||
|
||||
game:GetService("Players").PlayerAdded:connect(function(player)
|
||||
print("Player " .. player.userId .. " joining")
|
||||
player.CharacterAdded:connect(function(Character)
|
||||
addAttachment(Character.HumanoidRootPart, "RootRigAttachment")
|
||||
addAttachment(Character.Head, "FaceCenterAttachment")
|
||||
addAttachment(Character.Head, "FaceFrontAttachment", Vector3.new(0, 0, -0.6))
|
||||
addAttachment(Character.Head, "HairAttachment", Vector3.new(0, 0.6, 0))
|
||||
addAttachment(Character.Head, "HatAttachment", Vector3.new(0, 0.6, 0))
|
||||
addAttachment(Character.Head, "NeckRigAttachment", Vector3.new(0, -0.5, 0))
|
||||
|
||||
end)
|
||||
local presenceargs = {
|
||||
["game"] = placeId,
|
||||
["player"] = player.userId,
|
||||
["name"] = player.Name,
|
||||
["action"] = "joining"
|
||||
}
|
||||
HttpService:PostAsync(
|
||||
url .. "/api/updategameinfo/updatepresence",
|
||||
HttpService:JSONEncode(presenceargs)
|
||||
)
|
||||
wait(2)
|
||||
local arguments = {
|
||||
["game"] = placeId,
|
||||
["players"] = #game:GetService("Players"):GetPlayers()
|
||||
}
|
||||
HttpService:PostAsync(
|
||||
url .. "/api/updategameinfo",
|
||||
HttpService:JSONEncode(arguments)
|
||||
)
|
||||
local visitarguments = {
|
||||
["game"] = placeId
|
||||
}
|
||||
HttpService:PostAsync(
|
||||
url .. "/api/updategameinfo/updatevisits",
|
||||
HttpService:JSONEncode(visitarguments)
|
||||
)
|
||||
end)
|
||||
|
||||
game:GetService("Players").PlayerRemoving:connect(function(player)
|
||||
print("Player " .. player.userId .. " leaving")
|
||||
local presenceargs = {
|
||||
["game"] = placeId,
|
||||
["player"] = player.userId,
|
||||
["name"] = player.Name,
|
||||
["action"] = "leaving"
|
||||
}
|
||||
HttpService:PostAsync(
|
||||
url .. "/api/updategameinfo/updatepresence",
|
||||
HttpService:JSONEncode(presenceargs)
|
||||
)
|
||||
wait(2)
|
||||
local arguments = {
|
||||
["game"] = placeId,
|
||||
["players"] = #game:GetService("Players"):GetPlayers()
|
||||
}
|
||||
HttpService:PostAsync(
|
||||
url .. "/api/updategameinfo",
|
||||
HttpService:JSONEncode(arguments)
|
||||
)
|
||||
if #game:GetService("Players"):GetPlayers() < 1 then
|
||||
print("Shutdown time")
|
||||
-- less than one player is in the game so lets shut down
|
||||
local arguments = {
|
||||
["game"] = placeId
|
||||
}
|
||||
HttpService:PostAsync(
|
||||
url .. "/api/updategameinfo/closejob",
|
||||
HttpService:JSONEncode(arguments)
|
||||
)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
|
||||
local StringToDetect = ";ec";
|
||||
|
||||
game:GetService("Players").PlayerAdded:connect(function(Player)
|
||||
Player.Chatted:connect(function(Message)
|
||||
if string.find(string.lower(Message), string.lower(StringToDetect)) then
|
||||
if Player.Character then
|
||||
Player.Character.Humanoid.Health = 0;
|
||||
end;
|
||||
end;
|
||||
end);
|
||||
end);
|
||||
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 301 KiB |
|
|
@ -0,0 +1 @@
|
|||
3b5f1470aa859d3782f72ba07c72ed7d7bc2e461f5f85bb9fd007bf66349d5ee
|
||||
|
|
@ -0,0 +1 @@
|
|||
4cd4d51885b3127d72cf4bbc3e889ec4afa5c4bd725dfba4beab239c2d51b7c5
|
||||
|
|
@ -0,0 +1 @@
|
|||
ecfbc1e4cadd0167cddf1c9920adadf7183f690d7101c1b84d51616a35fada55
|
||||
|
|
@ -0,0 +1 @@
|
|||
d650fafa3e969e786d874def30f32208dc1ebe57d051fc719fe8a0e75af339eb
|
||||
|
|
@ -0,0 +1 @@
|
|||
f13b90a25b1d1d3ff7dfc0628d6fe554cb3b4eb809fe7289632e41670effb197
|
||||
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 24.08"><defs><style>.cls-1{fill:#00a2ff;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="BC"><g id="BC-2" data-name="BC"><path class="cls-1" d="M30,8.58h2.1c1.3,0,2.3.39,2.3,1.6a1.37,1.37,0,0,1-1.1,1.4h0c.9.19,1.5.69,1.5,1.5,0,1.29-1.1,1.89-2.5,1.89H30Zm2,2.69c.9,0,1.3-.3,1.3-1s-.4-.8-1.3-.8h-.8v1.8Zm.1,2.91c1,0,1.5-.4,1.5-1.1s-.5-1-1.5-1h-1v2.1Z"/><path class="cls-1" d="M38.6,8.38a3,3,0,0,1,1.9.8l-.6.7a1.66,1.66,0,0,0-1.2-.5c-1.1,0-1.8.89-1.8,2.4s.7,2.4,1.8,2.4a1.82,1.82,0,0,0,1.4-.6l.6.7a2.52,2.52,0,0,1-2,.9c-1.7,0-3-1.2-3-3.4S36.9,8.38,38.6,8.38Z"/><path class="cls-1" d="M47,20.08H25a1,1,0,0,1,0-2H46v-12H25a1,1,0,0,1-1-1,.94.94,0,0,1,1-1H47a.94.94,0,0,1,1,1v14A.94.94,0,0,1,47,20.08Z"/><path class="cls-1" d="M17,4.08a.76.76,0,0,1-.4-.1L12,2.17,7.4,4a1,1,0,0,1-1.3-.6.93.93,0,0,1,.6-1.3l5-2a.78.78,0,0,1,.7,0l5,2a1,1,0,0,1-.4,2Z"/><path class="cls-1" d="M23.4,12.18,22,11.47V5.08a.89.89,0,0,0-.3-.7l-1-1a1,1,0,0,0-1.4,1.4l.7.7v6.6a1,1,0,0,0,.6.89l1.4.7v.41H2v-.4L3.4,13a1,1,0,0,0,.6-.9V5.48l.7-.7a1,1,0,0,0-1.4-1.4l-1,1a.89.89,0,0,0-.3.7v6.39l-1.4.7a1,1,0,0,0-.6.91v2a.94.94,0,0,0,1,1H2.1c.5,4.7,4.5,8,9.9,8s9.4-3.3,9.9-8H23a.94.94,0,0,0,1-1v-2A1,1,0,0,0,23.4,12.18ZM12,22.08c-4.3,0-7.4-2.4-7.9-6H19.9C19.4,19.68,16.3,22.08,12,22.08Z"/></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 23.97"><defs><style>.cls-1{fill:#f68802;}.cls-2{fill:#191919;}</style></defs><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="BC"><g id="OBC"><path class="cls-1" d="M26.3,11.67c0-2.1,1.2-3.4,2.9-3.4s2.9,1.2,2.9,3.4-1.2,3.4-2.9,3.4S26.3,13.77,26.3,11.67Zm4.6,0c0-1.5-.7-2.3-1.7-2.3s-1.7.9-1.7,2.3.7,2.4,1.7,2.4S30.9,13.17,30.9,11.67Z"/><path class="cls-1" d="M33.3,8.47h2.1c1.3,0,2.3.4,2.3,1.6a1.37,1.37,0,0,1-1.1,1.4h0c.9.2,1.5.7,1.5,1.5,0,1.3-1.1,1.9-2.5,1.9H33.3Zm2,2.7c.9,0,1.3-.3,1.3-1s-.4-.8-1.3-.8h-.8v1.8Zm.2,2.9c1,0,1.5-.4,1.5-1.1s-.5-1-1.5-1h-1v2.1Z"/><path class="cls-1" d="M41.9,8.27a3,3,0,0,1,1.9.81l-.6.69a1.66,1.66,0,0,0-1.2-.5c-1.1,0-1.8.91-1.8,2.41s.7,2.4,1.8,2.4a1.82,1.82,0,0,0,1.4-.6l.6.7a2.55,2.55,0,0,1-2,.9c-1.7,0-3-1.2-3-3.4A3,3,0,0,1,41.9,8.27Z"/><path class="cls-2" d="M47,20H25a1,1,0,0,1,0-2H46V6H25a.94.94,0,0,1-1-1,.94.94,0,0,1,1-1H47a.94.94,0,0,1,1,1V19A.94.94,0,0,1,47,20Z"/><path class="cls-1" d="M17,4a.76.76,0,0,1-.4-.1L12,2.07,7.4,4a1,1,0,0,1-1.3-.6.93.93,0,0,1,.6-1.3l5-2a.94.94,0,0,1,.7,0l5,2a1,1,0,0,1,.6,1.3A1.1,1.1,0,0,1,17,4Z"/><path class="cls-1" d="M17,8a.76.76,0,0,1-.4-.1L12,6.07,7.4,8a1,1,0,0,1-1.3-.6.93.93,0,0,1,.6-1.3l5-2a.85.85,0,0,1,.7,0l5,2a1,1,0,0,1,.6,1.3A1.1,1.1,0,0,1,17,8Z"/><path class="cls-1" d="M17,12a.76.76,0,0,1-.4-.1L12,10.07,7.4,12a1,1,0,0,1-1.3-.6.93.93,0,0,1,.6-1.3l5-2a.85.85,0,0,1,.7,0l5,2a1,1,0,0,1,.6,1.3A1.1,1.1,0,0,1,17,12Z"/><path class="cls-2" d="M23.4,12.07l-1.4-.7V5a.91.91,0,0,0-.3-.7l-1-1a1,1,0,1,0-1.4,1.4l.7.7V12a1,1,0,0,0,.6.9l1.4.7V14H2v-.4l1.4-.7A1,1,0,0,0,4,12V5.37l.7-.7a1,1,0,1,0-1.4-1.4l-1,1A.91.91,0,0,0,2,5v6.4l-1.4.7A1,1,0,0,0,0,13v2a.94.94,0,0,0,1,1H2.1c.5,4.7,4.5,8,9.9,8s9.4-3.3,9.9-8H23a.94.94,0,0,0,1-1V13A1,1,0,0,0,23.4,12.07ZM12,22c-4.3,0-7.4-2.4-7.9-6H19.9C19.4,19.57,16.3,22,12,22Z"/></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 100 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 69 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 195 KiB |
|
After Width: | Height: | Size: 16 MiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
|
@ -0,0 +1,114 @@
|
|||
--rbxassetid%854%
|
||||
-- Creates all neccessary scripts for the gui on initial load, everything except build tools
|
||||
-- Created by Ben T. 10/29/10
|
||||
-- Please note that these are loaded in a specific order to diminish errors/perceived load time by user
|
||||
|
||||
local scriptContext = game:GetService("ScriptContext")
|
||||
local touchEnabled = false
|
||||
pcall(function() touchEnabled = game:GetService("UserInputService").TouchEnabled end)
|
||||
|
||||
-- library registration
|
||||
scriptContext:AddCoreScript(855, scriptContext,"/Libraries/LibraryRegistration/LibraryRegistration")
|
||||
|
||||
local function waitForChild(instance, name)
|
||||
while not instance:FindFirstChild(name) do
|
||||
instance.ChildAdded:wait()
|
||||
end
|
||||
end
|
||||
local function waitForProperty(instance, property)
|
||||
while not instance[property] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
|
||||
-- Responsible for tracking logging items
|
||||
local scriptContext = game:GetService("ScriptContext")
|
||||
scriptContext:AddCoreScript(856, scriptContext, "CoreScripts/Sections")
|
||||
|
||||
waitForChild(game:GetService("CoreGui"),"RobloxGui")
|
||||
local screenGui = game:GetService("CoreGui"):FindFirstChild("RobloxGui")
|
||||
|
||||
-- SettingsScript
|
||||
scriptContext:AddCoreScript(857,screenGui,"CoreScripts/Settings")
|
||||
|
||||
if not touchEnabled then
|
||||
-- ToolTipper (creates tool tips for gui)
|
||||
scriptContext:AddCoreScript(858,screenGui,"CoreScripts/ToolTip")
|
||||
else
|
||||
scriptContext:AddCoreScript(859,screenGui,"CoreScripts/TouchControls")
|
||||
end
|
||||
|
||||
-- MainBotChatScript
|
||||
scriptContext:AddCoreScript(860,screenGui,"CoreScripts/MainBotChatScript")
|
||||
|
||||
-- Developer Console Script
|
||||
scriptContext:AddCoreScript(861,screenGui,"CoreScripts/DeveloperConsole")
|
||||
|
||||
-- Popup Script
|
||||
scriptContext:AddCoreScript(862,screenGui,"CoreScripts/PopupScript")
|
||||
-- Friend Notification Script (probably can use this script to expand out to other notifications)
|
||||
scriptContext:AddCoreScript(863,screenGui,"CoreScripts/NotificationScript")
|
||||
-- Chat script
|
||||
scriptContext:AddCoreScript(864, screenGui, "CoreScripts/ChatScript")
|
||||
-- Purchase Prompt Script
|
||||
scriptContext:AddCoreScript(865, screenGui, "CoreScripts/PurchasePromptScript")
|
||||
-- Health Script
|
||||
scriptContext:AddCoreScript(866, screenGui, "CoreScripts/HealthScript")
|
||||
|
||||
if not touchEnabled then
|
||||
-- New Player List
|
||||
scriptContext:AddCoreScript(867,screenGui,"CoreScripts/PlayerListScript")
|
||||
elseif screenGui.AbsoluteSize.Y > 600 then
|
||||
-- New Player List
|
||||
scriptContext:AddCoreScript(867,screenGui,"CoreScripts/PlayerListScript")
|
||||
else
|
||||
delay(5, function()
|
||||
if screenGui.AbsoluteSize.Y >= 600 then
|
||||
-- New Player List
|
||||
scriptContext:AddCoreScript(867,screenGui,"CoreScripts/PlayerListScript")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if game.CoreGui.Version >= 3 then
|
||||
-- Backpack Builder, creates most of the backpack gui
|
||||
scriptContext:AddCoreScript(868,screenGui,"CoreScripts/BackpackScripts/BackpackBuilder")
|
||||
|
||||
waitForChild(screenGui,"CurrentLoadout")
|
||||
waitForChild(screenGui,"Backpack")
|
||||
local Backpack = screenGui.Backpack
|
||||
|
||||
-- Manager handles all big backpack state changes, other scripts subscribe to this and do things accordingly
|
||||
if game.CoreGui.Version >= 7 then
|
||||
scriptContext:AddCoreScript(869,Backpack,"CoreScripts/BackpackScripts/BackpackManager")
|
||||
end
|
||||
|
||||
-- Backpack Gear (handles all backpack gear tab stuff)
|
||||
game:GetService("ScriptContext"):AddCoreScript(870,Backpack,"CoreScripts/BackpackScripts/BackpackGear")
|
||||
-- Loadout Script, used for gear hotkeys
|
||||
scriptContext:AddCoreScript(871,screenGui.CurrentLoadout,"CoreScripts/BackpackScripts/LoadoutScript")
|
||||
if game.CoreGui.Version >= 8 then
|
||||
-- Wardrobe script handles all character dressing operations
|
||||
scriptContext:AddCoreScript(-1,Backpack,"CoreScripts/BackpackScripts/BackpackWardrobe")
|
||||
end
|
||||
end
|
||||
|
||||
local IsPersonalServer = not not game.Workspace:FindFirstChild("PSVariable")
|
||||
if IsPersonalServer then
|
||||
game:GetService("ScriptContext"):AddCoreScript(872,game.Players.LocalPlayer,"BuildToolManager")
|
||||
end
|
||||
game.Workspace.ChildAdded:connect(function(nchild)
|
||||
if nchild.Name=='PSVariable' and nchild:IsA('BoolValue') then
|
||||
IsPersonalServer = true
|
||||
game:GetService("ScriptContext"):AddCoreScript(872,game.Players.LocalPlayer,"BuildToolManager")
|
||||
end
|
||||
end)
|
||||
|
||||
if touchEnabled then -- touch devices don't use same control frame
|
||||
-- only used for touch device button generation
|
||||
scriptContext:AddCoreScript(873,screenGui,"CoreScripts/ContextActionTouch")
|
||||
|
||||
waitForChild(screenGui, 'ControlFrame')
|
||||
waitForChild(screenGui.ControlFrame, 'BottomLeftControl')
|
||||
screenGui.ControlFrame.BottomLeftControl.Visible = false
|
||||
end
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
--rbxassetid%855%
|
||||
-- Library Registration Script
|
||||
-- This script is used to register RbxLua libraries on game servers, so game scripts have
|
||||
-- access to all of the libraries (otherwise only local scripts do)
|
||||
|
||||
local sc = game:GetService("ScriptContext")
|
||||
local tries = 0
|
||||
|
||||
while not sc and tries < 3 do
|
||||
tries = tries + 1
|
||||
sc = game:GetService("ScriptContext")
|
||||
wait(0.2)
|
||||
end
|
||||
|
||||
if sc then
|
||||
sc:RegisterLibrary("Libraries/RbxGui", "874")
|
||||
sc:RegisterLibrary("Libraries/RbxGear", "875")
|
||||
sc:RegisterLibrary("Libraries/RbxUtility", "876")
|
||||
sc:RegisterLibrary("Libraries/RbxStamper", "877")
|
||||
sc:LibraryRegistrationComplete()
|
||||
else
|
||||
print("failed to find script context, libraries did not load")
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
--rbxassetid%856%
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
--rbxassetid%858%
|
||||
local controlFrame = script.Parent:FindFirstChild("ControlFrame")
|
||||
|
||||
if not controlFrame then return end
|
||||
|
||||
local topLeftControl = controlFrame:FindFirstChild("TopLeftControl")
|
||||
local bottomLeftControl = controlFrame:FindFirstChild("BottomLeftControl")
|
||||
local bottomRightControl = controlFrame:FindFirstChild("BottomRightControl")
|
||||
|
||||
|
||||
local frameTip = Instance.new("TextLabel")
|
||||
frameTip.Name = "ToolTip"
|
||||
frameTip.Text = ""
|
||||
frameTip.Font = Enum.Font.ArialBold
|
||||
frameTip.FontSize = Enum.FontSize.Size12
|
||||
frameTip.TextColor3 = Color3.new(1,1,1)
|
||||
frameTip.BorderSizePixel = 0
|
||||
frameTip.ZIndex = 10
|
||||
frameTip.Size = UDim2.new(2,0,1,0)
|
||||
frameTip.Position = UDim2.new(1,0,0,0)
|
||||
frameTip.BackgroundColor3 = Color3.new(0,0,0)
|
||||
frameTip.BackgroundTransparency = 1
|
||||
frameTip.TextTransparency = 1
|
||||
frameTip.TextWrap = true
|
||||
|
||||
local inside = Instance.new("BoolValue")
|
||||
inside.Name = "inside"
|
||||
inside.Value = false
|
||||
inside.Parent = frameTip
|
||||
|
||||
function setUpListeners(frameToListen)
|
||||
local fadeSpeed = 0.1
|
||||
frameToListen.Parent.MouseEnter:connect(function()
|
||||
if frameToListen:FindFirstChild("inside") then
|
||||
frameToListen.inside.Value = true
|
||||
wait(1.2)
|
||||
if frameToListen.inside.Value then
|
||||
while frameToListen.inside.Value and frameToListen.BackgroundTransparency > 0 do
|
||||
frameToListen.BackgroundTransparency = frameToListen.BackgroundTransparency - fadeSpeed
|
||||
frameToListen.TextTransparency = frameToListen.TextTransparency - fadeSpeed
|
||||
wait()
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
function killTip(killFrame)
|
||||
killFrame.inside.Value = false
|
||||
killFrame.BackgroundTransparency = 1
|
||||
killFrame.TextTransparency = 1
|
||||
end
|
||||
frameToListen.Parent.MouseLeave:connect(function() killTip(frameToListen) end)
|
||||
frameToListen.Parent.MouseButton1Click:connect(function() killTip(frameToListen) end)
|
||||
end
|
||||
|
||||
function createSettingsButtonTip(parent)
|
||||
if parent == nil then
|
||||
parent = bottomLeftControl:FindFirstChild("SettingsButton")
|
||||
end
|
||||
|
||||
local toolTip = frameTip:clone()
|
||||
toolTip.RobloxLocked = true
|
||||
toolTip.Text = "Settings/Leave Game"
|
||||
toolTip.Position = UDim2.new(0,0,0,-18)
|
||||
toolTip.Size = UDim2.new(0,120,0,20)
|
||||
toolTip.Parent = parent
|
||||
setUpListeners(toolTip)
|
||||
end
|
||||
|
||||
wait(5) -- make sure we are loaded in, won't need tool tips for first 5 seconds anyway
|
||||
|
||||
---------------- set up Bottom Left Tool Tips -------------------------
|
||||
|
||||
local bottomLeftChildren = bottomLeftControl:GetChildren()
|
||||
local hasSettingsTip = false
|
||||
|
||||
for i = 1, #bottomLeftChildren do
|
||||
|
||||
if bottomLeftChildren[i].Name == "Exit" then
|
||||
local exitTip = frameTip:clone()
|
||||
exitTip.RobloxLocked = true
|
||||
exitTip.Text = "Leave Place"
|
||||
exitTip.Position = UDim2.new(0,0,-1,0)
|
||||
exitTip.Size = UDim2.new(1,0,1,0)
|
||||
exitTip.Parent = bottomLeftChildren[i]
|
||||
setUpListeners(exitTip)
|
||||
elseif bottomLeftChildren[i].Name == "SettingsButton" then
|
||||
hasSettingsTip = true
|
||||
createSettingsButtonTip(bottomLeftChildren[i])
|
||||
end
|
||||
end
|
||||
|
||||
---------------- set up Bottom Right Tool Tips -------------------------
|
||||
|
||||
local bottomRightChildren = bottomRightControl:GetChildren()
|
||||
|
||||
for i = 1, #bottomRightChildren do
|
||||
if bottomRightChildren[i].Name:find("Camera") ~= nil then
|
||||
local cameraTip = frameTip:clone()
|
||||
cameraTip.RobloxLocked = true
|
||||
cameraTip.Text = "Camera View"
|
||||
if bottomRightChildren[i].Name:find("Zoom") then
|
||||
cameraTip.Position = UDim2.new(-1,0,-1.5)
|
||||
else
|
||||
cameraTip.Position = UDim2.new(0,0,-1.5,0)
|
||||
end
|
||||
cameraTip.Size = UDim2.new(2,0,1.25,0)
|
||||
cameraTip.Parent = bottomRightChildren[i]
|
||||
setUpListeners(cameraTip)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,852 @@
|
|||
--rbxassetid%859%
|
||||
-- This is responsible for all touch controls we show (as of this writing, only on iOS)
|
||||
-- this includes character move thumbsticks, and buttons for jump, use of items, camera, etc.
|
||||
-- Written by Ben Tkacheff, Copyright Roblox 2013
|
||||
|
||||
-- obligatory stuff to make sure we don't access nil data
|
||||
while not Game do
|
||||
wait()
|
||||
end
|
||||
while not Game:FindFirstChild("Players") do
|
||||
wait()
|
||||
end
|
||||
while not Game.Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
while not Game:FindFirstChild("CoreGui") do
|
||||
wait()
|
||||
end
|
||||
while not Game.CoreGui:FindFirstChild("RobloxGui") do
|
||||
wait()
|
||||
end
|
||||
|
||||
local userInputService = Game:GetService("UserInputService")
|
||||
local success = pcall(function() userInputService:IsLuaTouchControls() end)
|
||||
if not success then
|
||||
script:Destroy()
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------
|
||||
-- Variables
|
||||
local screenResolution = Game:GetService("GuiService"):GetScreenResolution()
|
||||
function isSmallScreenDevice()
|
||||
return screenResolution.y <= 500
|
||||
end
|
||||
|
||||
local GameSettings = UserSettings().GameSettings
|
||||
|
||||
local localPlayer = Game.Players.LocalPlayer
|
||||
|
||||
local isInThumbstickMode = false
|
||||
|
||||
local thumbstickInactiveAlpha = 0.3
|
||||
local thumbstickSize = 120
|
||||
if isSmallScreenDevice() then
|
||||
thumbstickSize = 70
|
||||
end
|
||||
|
||||
local touchControlsSheet = "rbxasset://textures/ui/TouchControlsSheet.png"
|
||||
local DPadSheet = "rbxasset://textures/ui/DPadSheet.png"
|
||||
local ThumbstickDeadZone = 5
|
||||
local ThumbstickMaxPercentGive = 0.92
|
||||
local thumbstickTouches = {}
|
||||
|
||||
local jumpButtonSize = 90
|
||||
if isSmallScreenDevice() then
|
||||
jumpButtonSize = 70
|
||||
end
|
||||
local oldJumpTouches = {}
|
||||
local currentJumpTouch = nil
|
||||
|
||||
local CameraRotateSensitivity = 0.007
|
||||
local CameraRotateDeadZone = CameraRotateSensitivity * 16
|
||||
local CameraZoomSensitivity = 0.03
|
||||
local PinchZoomDelay = 0.2
|
||||
local cameraTouch = nil
|
||||
local dpadTouch = nil
|
||||
|
||||
|
||||
-- make sure all of our images are good to go
|
||||
Game:GetService("ContentProvider"):Preload(touchControlsSheet)
|
||||
Game:GetService("ContentProvider"):Preload(DPadSheet)
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------
|
||||
-- Functions
|
||||
|
||||
local isPointInRect = function(point, rectPos, rectSize)
|
||||
if point.x >= rectPos.x and point.x <= (rectPos.x + rectSize.x) then
|
||||
if point.y >= rectPos.y and point.y <= (rectPos.y + rectSize.y) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Thumbstick Control
|
||||
--
|
||||
|
||||
function setCameraTouch(newTouch)
|
||||
cameraTouch = newTouch
|
||||
if newTouch == nil then
|
||||
pcall(function() userInputService.InCameraGesture = false end)
|
||||
else
|
||||
pcall(function() userInputService.InCameraGesture = true end)
|
||||
end
|
||||
end
|
||||
|
||||
function DistanceBetweenTwoPoints(point1, point2)
|
||||
local dx = point2.x - point1.x
|
||||
local dy = point2.y - point1.y
|
||||
return math.sqrt( (dx*dx) + (dy*dy) )
|
||||
end
|
||||
|
||||
function transformFromCenterToTopLeft(pointToTranslate, guiObject)
|
||||
return UDim2.new(0,pointToTranslate.x - guiObject.AbsoluteSize.x/2,0,pointToTranslate.y - guiObject.AbsoluteSize.y/2)
|
||||
end
|
||||
|
||||
function rotatePointAboutLocation(pointToRotate, pointToRotateAbout, radians)
|
||||
local sinAnglePercent = math.sin(radians)
|
||||
local cosAnglePercent = math.cos(radians)
|
||||
|
||||
local transformedPoint = pointToRotate
|
||||
|
||||
-- translate point back to origin:
|
||||
transformedPoint = Vector2.new(transformedPoint.x - pointToRotateAbout.x, transformedPoint.y - pointToRotateAbout.y)
|
||||
|
||||
-- rotate point
|
||||
local xNew = transformedPoint.x * cosAnglePercent - transformedPoint.y * sinAnglePercent
|
||||
local yNew = transformedPoint.x * sinAnglePercent + transformedPoint.y * cosAnglePercent
|
||||
|
||||
-- translate point back:
|
||||
transformedPoint = Vector2.new(xNew + pointToRotateAbout.x, yNew + pointToRotateAbout.y)
|
||||
|
||||
return transformedPoint
|
||||
end
|
||||
|
||||
function dotProduct(v1,v2)
|
||||
return ((v1.x*v2.x) + (v1.y*v2.y))
|
||||
end
|
||||
|
||||
function stationaryThumbstickTouchMove(thumbstickFrame, thumbstickOuter, touchLocation)
|
||||
local thumbstickOuterCenterPosition = Vector2.new(thumbstickOuter.Position.X.Offset + thumbstickOuter.AbsoluteSize.x/2, thumbstickOuter.Position.Y.Offset + thumbstickOuter.AbsoluteSize.y/2)
|
||||
local centerDiff = DistanceBetweenTwoPoints(touchLocation, thumbstickOuterCenterPosition)
|
||||
|
||||
-- thumbstick is moving outside our region, need to cap its distance
|
||||
if centerDiff > (thumbstickSize/2) then
|
||||
local thumbVector = Vector2.new(touchLocation.x - thumbstickOuterCenterPosition.x,touchLocation.y - thumbstickOuterCenterPosition.y);
|
||||
local normal = thumbVector.unit
|
||||
if normal.x == math.nan or normal.x == math.inf then
|
||||
normal = Vector2.new(0,normal.y)
|
||||
end
|
||||
if normal.y == math.nan or normal.y == math.inf then
|
||||
normal = Vector2.new(normal.x,0)
|
||||
end
|
||||
|
||||
local newThumbstickInnerPosition = thumbstickOuterCenterPosition + (normal * (thumbstickSize/2))
|
||||
thumbstickFrame.Position = transformFromCenterToTopLeft(newThumbstickInnerPosition, thumbstickFrame)
|
||||
else
|
||||
thumbstickFrame.Position = transformFromCenterToTopLeft(touchLocation,thumbstickFrame)
|
||||
end
|
||||
|
||||
return Vector2.new(thumbstickFrame.Position.X.Offset - thumbstickOuter.Position.X.Offset,thumbstickFrame.Position.Y.Offset - thumbstickOuter.Position.Y.Offset)
|
||||
end
|
||||
|
||||
function followThumbstickTouchMove(thumbstickFrame, thumbstickOuter, touchLocation)
|
||||
local thumbstickOuterCenter = Vector2.new(thumbstickOuter.Position.X.Offset + thumbstickOuter.AbsoluteSize.x/2, thumbstickOuter.Position.Y.Offset + thumbstickOuter.AbsoluteSize.y/2)
|
||||
|
||||
-- thumbstick is moving outside our region, need to position outer thumbstick texture carefully (to make look and feel like actual joystick controller)
|
||||
if DistanceBetweenTwoPoints(touchLocation, thumbstickOuterCenter) > thumbstickSize/2 then
|
||||
local thumbstickInnerCenter = Vector2.new(thumbstickFrame.Position.X.Offset + thumbstickFrame.AbsoluteSize.x/2, thumbstickFrame.Position.Y.Offset + thumbstickFrame.AbsoluteSize.y/2)
|
||||
local movementVectorUnit = Vector2.new(touchLocation.x - thumbstickInnerCenter.x, touchLocation.y - thumbstickInnerCenter.y).unit
|
||||
|
||||
local outerToInnerVectorCurrent = Vector2.new(thumbstickInnerCenter.x - thumbstickOuterCenter.x, thumbstickInnerCenter.y - thumbstickOuterCenter.y)
|
||||
local outerToInnerVectorCurrentUnit = outerToInnerVectorCurrent.unit
|
||||
local movementVector = Vector2.new(touchLocation.x - thumbstickInnerCenter.x, touchLocation.y - thumbstickInnerCenter.y)
|
||||
|
||||
-- First, find the angle between the new thumbstick movement vector,
|
||||
-- and the vector between thumbstick inner and thumbstick outer.
|
||||
-- We will use this to pivot thumbstick outer around thumbstick inner, gives a nice joystick feel
|
||||
local crossOuterToInnerWithMovement = (outerToInnerVectorCurrentUnit.x * movementVectorUnit.y) - (outerToInnerVectorCurrentUnit.y * movementVectorUnit.x)
|
||||
local angle = math.atan2(crossOuterToInnerWithMovement, dotProduct(outerToInnerVectorCurrentUnit, movementVectorUnit))
|
||||
local anglePercent = angle * math.min( (movementVector.magnitude)/(outerToInnerVectorCurrent.magnitude), 1.0);
|
||||
|
||||
-- If angle is significant, rotate about the inner thumbsticks current center
|
||||
if math.abs(anglePercent) > 0.00001 then
|
||||
local outerThumbCenter = rotatePointAboutLocation(thumbstickOuterCenter, thumbstickInnerCenter, anglePercent)
|
||||
thumbstickOuter.Position = transformFromCenterToTopLeft(Vector2.new(outerThumbCenter.x,outerThumbCenter.y), thumbstickOuter)
|
||||
end
|
||||
|
||||
-- now just translate outer thumbstick to make sure it stays nears inner thumbstick
|
||||
thumbstickOuter.Position = UDim2.new(0,thumbstickOuter.Position.X.Offset+movementVector.x,0,thumbstickOuter.Position.Y.Offset+movementVector.y)
|
||||
end
|
||||
|
||||
thumbstickFrame.Position = transformFromCenterToTopLeft(touchLocation,thumbstickFrame)
|
||||
|
||||
-- a bit of error checking to make sure thumbsticks stay close to eachother
|
||||
thumbstickFramePosition = Vector2.new(thumbstickFrame.Position.X.Offset,thumbstickFrame.Position.Y.Offset)
|
||||
thumbstickOuterPosition = Vector2.new(thumbstickOuter.Position.X.Offset,thumbstickOuter.Position.Y.Offset)
|
||||
if DistanceBetweenTwoPoints(thumbstickFramePosition, thumbstickOuterPosition) > thumbstickSize/2 then
|
||||
local vectorWithLength = (thumbstickOuterPosition - thumbstickFramePosition).unit * thumbstickSize/2
|
||||
thumbstickOuter.Position = UDim2.new(0,thumbstickFramePosition.x + vectorWithLength.x,0,thumbstickFramePosition.y + vectorWithLength.y)
|
||||
end
|
||||
|
||||
return Vector2.new(thumbstickFrame.Position.X.Offset - thumbstickOuter.Position.X.Offset,thumbstickFrame.Position.Y.Offset - thumbstickOuter.Position.Y.Offset)
|
||||
end
|
||||
|
||||
function movementOutsideDeadZone(movementVector)
|
||||
return ( (math.abs(movementVector.x) > ThumbstickDeadZone) or (math.abs(movementVector.y) > ThumbstickDeadZone) )
|
||||
end
|
||||
|
||||
function constructThumbstick(defaultThumbstickPos, updateFunction, stationaryThumbstick)
|
||||
local thumbstickFrame = Instance.new("Frame")
|
||||
thumbstickFrame.Name = "ThumbstickFrame"
|
||||
thumbstickFrame.Active = true
|
||||
thumbstickFrame.Size = UDim2.new(0,thumbstickSize,0,thumbstickSize)
|
||||
thumbstickFrame.Position = defaultThumbstickPos
|
||||
thumbstickFrame.BackgroundTransparency = 1
|
||||
|
||||
local outerThumbstick = Instance.new("ImageLabel")
|
||||
outerThumbstick.Name = "OuterThumbstick"
|
||||
outerThumbstick.Image = touchControlsSheet
|
||||
outerThumbstick.ImageRectOffset = Vector2.new(0,0)
|
||||
outerThumbstick.ImageRectSize = Vector2.new(220,220)
|
||||
outerThumbstick.BackgroundTransparency = 1
|
||||
outerThumbstick.Size = UDim2.new(0,thumbstickSize,0,thumbstickSize)
|
||||
outerThumbstick.Position = defaultThumbstickPos
|
||||
outerThumbstick.Parent = Game.CoreGui.RobloxGui
|
||||
|
||||
local innerThumbstick = Instance.new("ImageLabel")
|
||||
innerThumbstick.Name = "InnerThumbstick"
|
||||
innerThumbstick.Image = touchControlsSheet
|
||||
innerThumbstick.ImageRectOffset = Vector2.new(220,0)
|
||||
innerThumbstick.ImageRectSize = Vector2.new(111,111)
|
||||
innerThumbstick.BackgroundTransparency = 1
|
||||
innerThumbstick.Size = UDim2.new(0,thumbstickSize/2,0,thumbstickSize/2)
|
||||
innerThumbstick.Position = UDim2.new(0, thumbstickFrame.Size.X.Offset/2 - thumbstickSize/4, 0, thumbstickFrame.Size.Y.Offset/2 - thumbstickSize/4)
|
||||
innerThumbstick.Parent = thumbstickFrame
|
||||
innerThumbstick.ZIndex = 2
|
||||
|
||||
local thumbstickTouch = nil
|
||||
local userInputServiceTouchMovedCon = nil
|
||||
local userInputSeviceTouchEndedCon = nil
|
||||
|
||||
local startInputTracking = function(inputObject)
|
||||
if thumbstickTouch then return end
|
||||
if inputObject == cameraTouch then return end
|
||||
if inputObject == currentJumpTouch then return end
|
||||
if inputObject.UserInputType ~= Enum.UserInputType.Touch then return end
|
||||
|
||||
thumbstickTouch = inputObject
|
||||
table.insert(thumbstickTouches,thumbstickTouch)
|
||||
|
||||
thumbstickFrame.Position = transformFromCenterToTopLeft(thumbstickTouch.Position,thumbstickFrame)
|
||||
outerThumbstick.Position = thumbstickFrame.Position
|
||||
|
||||
userInputServiceTouchMovedCon = userInputService.TouchMoved:connect(function(movedInput)
|
||||
if movedInput == thumbstickTouch then
|
||||
local movementVector = nil
|
||||
if stationaryThumbstick then
|
||||
movementVector = stationaryThumbstickTouchMove(thumbstickFrame,outerThumbstick,Vector2.new(movedInput.Position.x,movedInput.Position.y))
|
||||
else
|
||||
movementVector = followThumbstickTouchMove(thumbstickFrame,outerThumbstick,Vector2.new(movedInput.Position.x,movedInput.Position.y))
|
||||
end
|
||||
|
||||
if updateFunction then
|
||||
updateFunction(movementVector,outerThumbstick.Size.X.Offset/2)
|
||||
end
|
||||
end
|
||||
end)
|
||||
userInputSeviceTouchEndedCon = userInputService.TouchEnded:connect(function(endedInput)
|
||||
if endedInput == thumbstickTouch then
|
||||
if updateFunction then
|
||||
updateFunction(Vector2.new(0,0),1)
|
||||
end
|
||||
|
||||
userInputSeviceTouchEndedCon:disconnect()
|
||||
userInputServiceTouchMovedCon:disconnect()
|
||||
|
||||
thumbstickFrame.Position = defaultThumbstickPos
|
||||
outerThumbstick.Position = defaultThumbstickPos
|
||||
|
||||
for i, object in pairs(thumbstickTouches) do
|
||||
if object == thumbstickTouch then
|
||||
table.remove(thumbstickTouches,i)
|
||||
break
|
||||
end
|
||||
end
|
||||
thumbstickTouch = nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
thumbstickFrame.Visible = not userInputService.ModalEnabled
|
||||
outerThumbstick.Visible = not userInputService.ModalEnabled
|
||||
|
||||
thumbstickFrame.InputBegan:connect(startInputTracking)
|
||||
return thumbstickFrame, outerThumbstick
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- DPad Control
|
||||
--
|
||||
|
||||
function createDPadArrowButton(name, parent, position, size, image, spriteOffset, spriteSize)
|
||||
local DPadArrow = Instance.new("ImageButton")
|
||||
DPadArrow.Name = name
|
||||
DPadArrow.Image = image
|
||||
DPadArrow.ImageRectOffset = spriteOffset
|
||||
DPadArrow.ImageRectSize = spriteSize
|
||||
DPadArrow.BackgroundTransparency = 1
|
||||
DPadArrow.Size = size
|
||||
DPadArrow.Position = position
|
||||
DPadArrow.Parent = parent
|
||||
return DPadArrow
|
||||
end
|
||||
|
||||
function createDPad()
|
||||
local DPadFrame = Instance.new("Frame")
|
||||
DPadFrame.Name = "DPadFrame"
|
||||
DPadFrame.Active = true
|
||||
DPadFrame.Size = UDim2.new(0,192,0,192)
|
||||
DPadFrame.Position = UDim2.new(0,10,1,-230)
|
||||
DPadFrame.BackgroundTransparency = 1
|
||||
|
||||
-- local image = "rbxassetid://133293265"
|
||||
local image = DPadSheet
|
||||
local bigSize = UDim2.new(0,64,0,64)
|
||||
local smallSize = UDim2.new(0,23,0,23)
|
||||
local spriteSizeLarge = Vector2.new(128, 128)
|
||||
local spriteSizeSmall = Vector2.new(46, 46)
|
||||
|
||||
createDPadArrowButton("BackButton", DPadFrame, UDim2.new(0.5, -32, 1, -64), bigSize, image, Vector2.new(0, 0), spriteSizeLarge)
|
||||
createDPadArrowButton("ForwardButton", DPadFrame, UDim2.new(0.5, -32, 0, 0), bigSize, image, Vector2.new(0, 258), spriteSizeLarge)
|
||||
createDPadArrowButton("JumpButton", DPadFrame, UDim2.new(0.5, -32, 0.5, -32), bigSize, image, Vector2.new(129, 0), spriteSizeLarge)
|
||||
createDPadArrowButton("LeftButton", DPadFrame, UDim2.new(0, 0, 0.5, -32), bigSize, image, Vector2.new(129,129), spriteSizeLarge)
|
||||
createDPadArrowButton("RightButton", DPadFrame, UDim2.new(1, -64, 0.5, -32), bigSize, image, Vector2.new(0, 129), spriteSizeLarge)
|
||||
createDPadArrowButton("forwardLeftButton", DPadFrame, UDim2.new(0, 35, 0, 35), smallSize, image, Vector2.new(129,258), spriteSizeSmall)
|
||||
createDPadArrowButton("forwardRightButton", DPadFrame, UDim2.new(1, -55, 0, 35), smallSize, image, Vector2.new(176,258), spriteSizeSmall)
|
||||
|
||||
return DPadFrame
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function setupDPadControls(DPadFrame)
|
||||
|
||||
local moveCharacterFunc = localPlayer.MoveCharacter
|
||||
DPadFrame.JumpButton.InputBegan:connect(function(inputObject)
|
||||
localPlayer:JumpCharacter()
|
||||
end)
|
||||
local movementVector = Vector2.new(0,0)
|
||||
|
||||
function setupButton(button,funcToCallBegin,funcToCallEnd)
|
||||
button.InputBegan:connect(function(inputObject)
|
||||
if not dpadTouch and inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin then
|
||||
dpadTouch = inputObject
|
||||
funcToCallBegin()
|
||||
end
|
||||
end)
|
||||
button.InputEnded:connect(function(inputObject)
|
||||
if dpadTouch == inputObject then
|
||||
if funcToCallEnd then
|
||||
funcToCallEnd()
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local forwardButtonBegin = function()
|
||||
movementVector = Vector2.new(0,-1)
|
||||
moveCharacterFunc(localPlayer, Vector2.new(0,-1), 1)
|
||||
|
||||
DPadFrame.forwardLeftButton.Visible = true
|
||||
DPadFrame.forwardRightButton.Visible = true
|
||||
end
|
||||
|
||||
local backwardButtonBegin = function()
|
||||
movementVector = Vector2.new(0,1)
|
||||
moveCharacterFunc(localPlayer, Vector2.new(0,1),1)
|
||||
end
|
||||
|
||||
local leftButtonBegin = function()
|
||||
movementVector = Vector2.new(-1,0)
|
||||
moveCharacterFunc(localPlayer, Vector2.new(-1,0),1)
|
||||
end
|
||||
|
||||
local rightButtonBegin = function()
|
||||
movementVector = Vector2.new(1,0)
|
||||
moveCharacterFunc(localPlayer, Vector2.new(1,0),1)
|
||||
end
|
||||
|
||||
DPadFrame.InputEnded:connect(function()
|
||||
DPadFrame.forwardLeftButton.Visible = false
|
||||
DPadFrame.forwardRightButton.Visible = false
|
||||
end)
|
||||
|
||||
local endStep = 0.08
|
||||
local endMovementFunc = function()
|
||||
DPadFrame.forwardLeftButton.Visible = false
|
||||
DPadFrame.forwardRightButton.Visible = false
|
||||
|
||||
Spawn(function()
|
||||
while not dpadTouch and movementVector ~= Vector2.new(0,0) do
|
||||
local newX = movementVector.x
|
||||
local newY = movementVector.y
|
||||
|
||||
if movementVector.x > 0 then
|
||||
newX = movementVector.x - endStep
|
||||
if newX < 0 then newX = 0 end
|
||||
elseif movementVector.x < 0 then
|
||||
newX = movementVector.x + endStep
|
||||
if newX > 0 then newX = 0 end
|
||||
end
|
||||
|
||||
if movementVector.y > 0 then
|
||||
newY = movementVector.y - endStep
|
||||
if newY < 0 then newY = 0 end
|
||||
elseif movementVector.y < 0 then
|
||||
newY = movementVector.y + endStep
|
||||
if newY > 0 then newY = 0 end
|
||||
end
|
||||
|
||||
movementVector = Vector2.new(newX,newY)
|
||||
moveCharacterFunc(localPlayer, movementVector,1)
|
||||
wait(1/60)
|
||||
end
|
||||
|
||||
if movementVector ~= Vector2.new(0,0) then
|
||||
movementVector = Vector2.new(0,0)
|
||||
moveCharacterFunc(localPlayer,Vector2.new(0,0) ,0)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local removeDiagonalButtons = function()
|
||||
if isPointInRect(dpadTouch.Position,DPadFrame.ForwardButton.AbsolutePosition,DPadFrame.ForwardButton.AbsoluteSize) then
|
||||
DPadFrame.forwardLeftButton.Visible = false
|
||||
DPadFrame.forwardRightButton.Visible = false
|
||||
end
|
||||
end
|
||||
|
||||
setupButton(DPadFrame.ForwardButton,forwardButtonBegin,removeDiagonalButtons)
|
||||
setupButton(DPadFrame.BackButton,backwardButtonBegin,nil)
|
||||
setupButton(DPadFrame.LeftButton,leftButtonBegin,nil)
|
||||
setupButton(DPadFrame.RightButton,rightButtonBegin,nil)
|
||||
|
||||
local getMovementVector = function(touchPosition)
|
||||
local xDiff = touchPosition.x - (DPadFrame.AbsolutePosition.x + DPadFrame.AbsoluteSize.x/2)
|
||||
local yDiff = touchPosition.y - (DPadFrame.AbsolutePosition.y + DPadFrame.AbsoluteSize.y/2)
|
||||
local vectorNew = Vector2.new(xDiff,yDiff)
|
||||
|
||||
movementVector = vectorNew.unit
|
||||
return vectorNew.unit
|
||||
end
|
||||
|
||||
Game:GetService("UserInputService").TouchMoved:connect(function(touchObject)
|
||||
if touchObject == dpadTouch then
|
||||
if isPointInRect(dpadTouch.Position,DPadFrame.AbsolutePosition,DPadFrame.AbsoluteSize) then
|
||||
moveCharacterFunc(localPlayer, getMovementVector(dpadTouch.Position),1)
|
||||
else
|
||||
endMovementFunc()
|
||||
end
|
||||
end
|
||||
end)
|
||||
Game:GetService("UserInputService").TouchEnded:connect(function(touchObject)
|
||||
if touchObject == dpadTouch then
|
||||
dpadTouch = nil
|
||||
endMovementFunc()
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
DPadFrame.Visible = not userInputService.ModalEnabled
|
||||
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- Character Movement
|
||||
--
|
||||
local characterThumbstick = nil
|
||||
local characterOuterThumbstick = nil
|
||||
|
||||
function setupCharacterMovement( parentFrame )
|
||||
local lastMovementVector, lastMaxMovement = nil
|
||||
local moveCharacterFunc = localPlayer.MoveCharacter
|
||||
local moveCharacterFunction = function ( movementVector, maxMovement )
|
||||
if localPlayer then
|
||||
if movementOutsideDeadZone(movementVector) then
|
||||
lastMovementVector = movementVector
|
||||
lastMaxMovement = maxMovement
|
||||
-- sometimes rounding error will not allow us to go max speed at some
|
||||
-- thumbstick angles, fix this with a bit of fudging near 100% throttle
|
||||
if movementVector.magnitude/maxMovement > ThumbstickMaxPercentGive then
|
||||
maxMovement = movementVector.magnitude - 1
|
||||
end
|
||||
moveCharacterFunc(localPlayer, movementVector, maxMovement)
|
||||
else
|
||||
lastMovementVector = Vector2.new(0,0)
|
||||
lastMaxMovement = 1
|
||||
moveCharacterFunc(localPlayer, lastMovementVector, lastMaxMovement)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local thumbstickPos = UDim2.new(0,thumbstickSize/2,1,-thumbstickSize*1.75)
|
||||
if isSmallScreenDevice() then
|
||||
thumbstickPos = UDim2.new(0,(thumbstickSize/2) - 10,1,-thumbstickSize - 20)
|
||||
end
|
||||
|
||||
characterThumbstick, characterOuterThumbstick = constructThumbstick(thumbstickPos, moveCharacterFunction, false)
|
||||
characterThumbstick.Name = "CharacterThumbstick"
|
||||
characterThumbstick.Parent = parentFrame
|
||||
|
||||
local refreshCharacterMovement = function()
|
||||
if localPlayer and isInThumbstickMode and moveCharacterFunc and lastMovementVector and lastMaxMovement then
|
||||
moveCharacterFunc(localPlayer, lastMovementVector, lastMaxMovement)
|
||||
end
|
||||
end
|
||||
return refreshCharacterMovement
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- Jump Button
|
||||
--
|
||||
local jumpButton = nil
|
||||
|
||||
function setupJumpButton( parentFrame )
|
||||
if (jumpButton == nil) then
|
||||
jumpButton = Instance.new("ImageButton")
|
||||
jumpButton.Name = "JumpButton"
|
||||
jumpButton.BackgroundTransparency = 1
|
||||
jumpButton.Image = touchControlsSheet
|
||||
jumpButton.ImageRectOffset = Vector2.new(176,222)
|
||||
jumpButton.ImageRectSize = Vector2.new(174,174)
|
||||
jumpButton.Size = UDim2.new(0,jumpButtonSize,0,jumpButtonSize)
|
||||
if isSmallScreenDevice() then
|
||||
jumpButton.Position = UDim2.new(1, -(jumpButtonSize*2.25), 1, -jumpButtonSize - 20)
|
||||
else
|
||||
jumpButton.Position = UDim2.new(1, -(jumpButtonSize*2.75), 1, -jumpButtonSize - 120)
|
||||
end
|
||||
|
||||
local playerJumpFunc = localPlayer.JumpCharacter
|
||||
|
||||
local doJumpLoop = function ()
|
||||
while currentJumpTouch do
|
||||
if localPlayer then
|
||||
playerJumpFunc(localPlayer)
|
||||
end
|
||||
wait(1/60)
|
||||
end
|
||||
end
|
||||
|
||||
jumpButton.InputBegan:connect(function(inputObject)
|
||||
if inputObject.UserInputType ~= Enum.UserInputType.Touch then return end
|
||||
if currentJumpTouch then return end
|
||||
if inputObject == cameraTouch then return end
|
||||
for i, touch in pairs(oldJumpTouches) do
|
||||
if touch == inputObject then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
currentJumpTouch = inputObject
|
||||
jumpButton.ImageRectOffset = Vector2.new(0,222)
|
||||
jumpButton.ImageRectSize = Vector2.new(174,174)
|
||||
doJumpLoop()
|
||||
end)
|
||||
jumpButton.InputEnded:connect(function (inputObject)
|
||||
if inputObject.UserInputType ~= Enum.UserInputType.Touch then return end
|
||||
|
||||
jumpButton.ImageRectOffset = Vector2.new(176,222)
|
||||
jumpButton.ImageRectSize = Vector2.new(174,174)
|
||||
|
||||
if inputObject == currentJumpTouch then
|
||||
table.insert(oldJumpTouches,currentJumpTouch)
|
||||
currentJumpTouch = nil
|
||||
end
|
||||
end)
|
||||
userInputService.InputEnded:connect(function ( globalInputObject )
|
||||
for i, touch in pairs(oldJumpTouches) do
|
||||
if touch == globalInputObject then
|
||||
table.remove(oldJumpTouches,i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end)
|
||||
jumpButton.Parent = parentFrame
|
||||
end
|
||||
jumpButton.Visible = not userInputService.ModalEnabled
|
||||
end
|
||||
|
||||
function isTouchUsedByJumpButton( touch )
|
||||
if touch == currentJumpTouch then return true end
|
||||
for i, touchToCompare in pairs(oldJumpTouches) do
|
||||
if touch == touchToCompare then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function isTouchUsedByThumbstick(touch)
|
||||
for i, touchToCompare in pairs(thumbstickTouches) do
|
||||
if touch == touchToCompare then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- Camera Control
|
||||
--
|
||||
|
||||
function setupCameraControl(parentFrame, refreshCharacterMoveFunc)
|
||||
local lastPos = nil
|
||||
local hasRotatedCamera = false
|
||||
local rotateCameraFunc = userInputService.RotateCamera
|
||||
|
||||
local pinchTime = -1
|
||||
local shouldPinch = false
|
||||
local lastPinchScale = nil
|
||||
local zoomCameraFunc = userInputService.ZoomCamera
|
||||
local pinchTouches = {}
|
||||
local pinchFrame = nil
|
||||
local pinchInputChangedCon = nil
|
||||
local pinchInputEndedCon = nil
|
||||
|
||||
local resetCameraRotateState = function()
|
||||
setCameraTouch(nil)
|
||||
hasRotatedCamera = false
|
||||
lastPos = nil
|
||||
end
|
||||
|
||||
local resetPinchState = function ()
|
||||
pinchTouches = {}
|
||||
|
||||
pinchTime = -1
|
||||
lastPinchScale = nil
|
||||
shouldPinch = false
|
||||
pinchFrame:Destroy()
|
||||
pinchFrame = nil
|
||||
end
|
||||
|
||||
local startPinch = function(firstTouch, secondTouch)
|
||||
-- track pinching in new frame
|
||||
if pinchFrame then pinchFrame:Destroy() end -- make sure we didn't track in any mud
|
||||
pinchFrame = Instance.new("Frame")
|
||||
pinchFrame.Name = "PinchFrame"
|
||||
pinchFrame.BackgroundTransparency = 1
|
||||
pinchFrame.Parent = parentFrame
|
||||
pinchFrame.Size = UDim2.new(1,0,1,0)
|
||||
|
||||
pinchFrame.InputChanged:connect(function(inputObject)
|
||||
if inputObject.UserInputType ~= Enum.UserInputType.Touch then return end
|
||||
|
||||
if not shouldPinch then
|
||||
resetPinchState()
|
||||
return
|
||||
end
|
||||
|
||||
if lastPinchScale == nil then -- first pinch move, just set up scale
|
||||
if inputObject == firstTouch then
|
||||
lastPinchScale = (inputObject.Position - secondTouch.Position).magnitude
|
||||
firstTouch = inputObject
|
||||
elseif inputObject == secondTouch then
|
||||
lastPinchScale = (inputObject.Position - firstTouch.Position).magnitude
|
||||
secondTouch = inputObject
|
||||
end
|
||||
else -- we are now actually pinching, do comparison to last pinch size
|
||||
local newPinchDistance = 0
|
||||
if inputObject == firstTouch then
|
||||
newPinchDistance = (inputObject.Position - secondTouch.Position).magnitude
|
||||
firstTouch = inputObject
|
||||
elseif inputObject == secondTouch then
|
||||
newPinchDistance = (inputObject.Position - firstTouch.Position).magnitude
|
||||
secondTouch = inputObject
|
||||
end
|
||||
if newPinchDistance ~= 0 then
|
||||
local pinchDiff = newPinchDistance - lastPinchScale
|
||||
if pinchDiff ~= 0 then
|
||||
zoomCameraFunc(userInputService, (pinchDiff * CameraZoomSensitivity))
|
||||
end
|
||||
lastPinchScale = newPinchDistance
|
||||
end
|
||||
end
|
||||
end)
|
||||
pinchFrame.InputEnded:connect(function(inputObject) -- pinch is over, destroy all
|
||||
if inputObject == firstTouch or inputObject == secondTouch then
|
||||
resetPinchState()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
local pinchGestureReceivedTouch = function(inputObject)
|
||||
if #pinchTouches < 1 then
|
||||
table.insert(pinchTouches,inputObject)
|
||||
pinchTime = tick()
|
||||
shouldPinch = false
|
||||
elseif #pinchTouches == 1 then
|
||||
shouldPinch = ( (tick() - pinchTime) <= PinchZoomDelay )
|
||||
|
||||
if shouldPinch then
|
||||
table.insert(pinchTouches,inputObject)
|
||||
startPinch(pinchTouches[1], pinchTouches[2])
|
||||
resetCameraRotateState()
|
||||
return true
|
||||
else -- shouldn't ever get here, but just in case
|
||||
pinchTouches = {}
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
parentFrame.InputBegan:connect(function (inputObject)
|
||||
if inputObject.UserInputType ~= Enum.UserInputType.Touch then return end
|
||||
if isTouchUsedByJumpButton(inputObject) then return end
|
||||
|
||||
local usedByThumbstick = isTouchUsedByThumbstick(inputObject)
|
||||
local isPinching = false
|
||||
if not usedByThumbstick then
|
||||
isPinching = pinchGestureReceivedTouch(inputObject)
|
||||
end
|
||||
|
||||
if cameraTouch == nil and not usedByThumbstick and not isPinching then
|
||||
setCameraTouch(inputObject)
|
||||
lastPos = Vector2.new(cameraTouch.Position.x,cameraTouch.Position.y)
|
||||
lastTick = tick()
|
||||
end
|
||||
end)
|
||||
|
||||
userInputService.InputChanged:connect(function (inputObject)
|
||||
if inputObject.UserInputType ~= Enum.UserInputType.Touch then return end
|
||||
if cameraTouch ~= inputObject then return end
|
||||
|
||||
local newPos = Vector2.new(cameraTouch.Position.x,cameraTouch.Position.y)
|
||||
local touchDiff = Vector2.new(0,0)
|
||||
if lastPos then
|
||||
touchDiff = (lastPos - newPos) * CameraRotateSensitivity
|
||||
end
|
||||
|
||||
-- first time rotating outside deadzone, just setup for next changed event
|
||||
if not hasRotatedCamera and (touchDiff.magnitude > CameraRotateDeadZone) then
|
||||
hasRotatedCamera = true
|
||||
lastPos = newPos
|
||||
end
|
||||
|
||||
-- fire everytime after we have rotated out of deadzone
|
||||
if hasRotatedCamera and (lastPos ~= newPos) then
|
||||
rotateCameraFunc(userInputService, touchDiff)
|
||||
refreshCharacterMoveFunc()
|
||||
lastPos = newPos
|
||||
end
|
||||
end)
|
||||
userInputService.InputEnded:connect(function (inputObject)
|
||||
if cameraTouch == inputObject or cameraTouch == nil then
|
||||
resetCameraRotateState()
|
||||
end
|
||||
|
||||
for i, touch in pairs(pinchTouches) do
|
||||
if touch == inputObject then
|
||||
table.remove(pinchTouches,i)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------
|
||||
--
|
||||
-- Touch Control
|
||||
--
|
||||
|
||||
local touchControlFrame = nil
|
||||
local characterDPad = nil
|
||||
|
||||
function setupTouchControls()
|
||||
touchControlFrame = Instance.new("Frame")
|
||||
touchControlFrame.Name = "TouchControlFrame"
|
||||
touchControlFrame.Size = UDim2.new(1,0,1,0)
|
||||
touchControlFrame.BackgroundTransparency = 1
|
||||
touchControlFrame.Parent = Game.CoreGui.RobloxGui
|
||||
|
||||
userInputService.ProcessedEvent:connect(function(inputObject, processed)
|
||||
if not processed then return end
|
||||
|
||||
-- kill camera pan if the touch is used by some user controls
|
||||
if inputObject == cameraTouch and inputObject.UserInputState == Enum.UserInputState.Begin then
|
||||
setCameraTouch(nil)
|
||||
end
|
||||
end)
|
||||
|
||||
setupJumpButton(touchControlFrame)
|
||||
local refreshCharacterMoveFunc = setupCharacterMovement(touchControlFrame)
|
||||
setupCameraControl(touchControlFrame, refreshCharacterMoveFunc)
|
||||
|
||||
characterDPad = createDPad()
|
||||
characterDPad.Name = "CharacterDPad"
|
||||
characterDPad.Parent = touchControlFrame
|
||||
setupDPadControls(characterDPad)
|
||||
|
||||
userInputService.Changed:connect(function(prop)
|
||||
if prop == "ModalEnabled" then
|
||||
activateTouchControls()
|
||||
end
|
||||
end)
|
||||
|
||||
activateTouchControls()
|
||||
end
|
||||
|
||||
function activateTouchControls()
|
||||
-- set user controlled visibility
|
||||
if userInputService.ModalEnabled then
|
||||
characterThumbstick.Visible = false
|
||||
characterOuterThumbstick.Visible = false
|
||||
jumpButton.Visible = false
|
||||
characterDPad.Visible = false
|
||||
else
|
||||
if (GameSettings.TouchMovementMode.Name == "Thumbstick" or GameSettings.TouchMovementMode.Name == "Default") then
|
||||
isInThumbstickMode = true
|
||||
else
|
||||
isInThumbstickMode = false
|
||||
end
|
||||
|
||||
characterThumbstick.Visible = isInThumbstickMode
|
||||
characterOuterThumbstick.Visible = isInThumbstickMode
|
||||
jumpButton.Visible = isInThumbstickMode
|
||||
characterDPad.Visible = not isInThumbstickMode
|
||||
end
|
||||
end
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
----------------------------------------------------------------------------
|
||||
-- Start of Script
|
||||
|
||||
if userInputService:IsLuaTouchControls() then
|
||||
setupTouchControls()
|
||||
else
|
||||
script:Destroy()
|
||||
end
|
||||
|
||||
GameSettings.Changed:connect(function(property)
|
||||
if (property == "TouchMovementMode") then
|
||||
activateTouchControls()
|
||||
end
|
||||
end)
|
||||
|
|
@ -0,0 +1,561 @@
|
|||
--rbxassetid%860%
|
||||
function waitForProperty(instance, name)
|
||||
while not instance[name] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
|
||||
function waitForChild(instance, name)
|
||||
while not instance:FindFirstChild(name) do
|
||||
instance.ChildAdded:wait()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local mainFrame
|
||||
local choices = {}
|
||||
local lastChoice
|
||||
local choiceMap = {}
|
||||
local currentConversationDialog
|
||||
local currentConversationPartner
|
||||
local currentAbortDialogScript
|
||||
|
||||
local tooFarAwayMessage = "You are too far away to chat!"
|
||||
local tooFarAwaySize = 300
|
||||
local characterWanderedOffMessage = "Chat ended because you walked away"
|
||||
local characterWanderedOffSize = 350
|
||||
local conversationTimedOut = "Chat ended because you didn't reply"
|
||||
local conversationTimedOutSize = 350
|
||||
|
||||
local player
|
||||
local screenGui
|
||||
local chatNotificationGui
|
||||
local messageDialog
|
||||
local timeoutScript
|
||||
local reenableDialogScript
|
||||
local dialogMap = {}
|
||||
local dialogConnections = {}
|
||||
|
||||
local gui = nil
|
||||
waitForChild(game,"CoreGui")
|
||||
waitForChild(game.CoreGui,"RobloxGui")
|
||||
if game.CoreGui.RobloxGui:FindFirstChild("ControlFrame") then
|
||||
gui = game.CoreGui.RobloxGui.ControlFrame
|
||||
else
|
||||
gui = game.CoreGui.RobloxGui
|
||||
end
|
||||
|
||||
function currentTone()
|
||||
if currentConversationDialog then
|
||||
return currentConversationDialog.Tone
|
||||
else
|
||||
return Enum.DialogTone.Neutral
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function createChatNotificationGui()
|
||||
chatNotificationGui = Instance.new("BillboardGui")
|
||||
chatNotificationGui.Name = "ChatNotificationGui"
|
||||
chatNotificationGui.ExtentsOffset = Vector3.new(0,1,0)
|
||||
chatNotificationGui.Size = UDim2.new(4, 0, 5.42857122, 0)
|
||||
chatNotificationGui.SizeOffset = Vector2.new(0,0)
|
||||
chatNotificationGui.StudsOffset = Vector3.new(0.4, 4.3, 0)
|
||||
chatNotificationGui.Enabled = true
|
||||
chatNotificationGui.RobloxLocked = true
|
||||
chatNotificationGui.Active = true
|
||||
|
||||
local image = Instance.new("ImageLabel")
|
||||
image.Name = "Image"
|
||||
image.Active = false
|
||||
image.BackgroundTransparency = 1
|
||||
image.Position = UDim2.new(0,0,0,0)
|
||||
image.Size = UDim2.new(1.0,0,1.0,0)
|
||||
image.Image = ""
|
||||
image.RobloxLocked = true
|
||||
image.Parent = chatNotificationGui
|
||||
|
||||
|
||||
local button = Instance.new("ImageButton")
|
||||
button.Name = "Button"
|
||||
button.AutoButtonColor = false
|
||||
button.Position = UDim2.new(0.0879999995, 0, 0.0529999994, 0)
|
||||
button.Size = UDim2.new(0.829999983, 0, 0.460000008, 0)
|
||||
button.Image = ""
|
||||
button.BackgroundTransparency = 1
|
||||
button.RobloxLocked = true
|
||||
button.Parent = image
|
||||
end
|
||||
|
||||
function getChatColor(tone)
|
||||
if tone == Enum.DialogTone.Neutral then
|
||||
return Enum.ChatColor.Blue
|
||||
elseif tone == Enum.DialogTone.Friendly then
|
||||
return Enum.ChatColor.Green
|
||||
elseif tone == Enum.DialogTone.Enemy then
|
||||
return Enum.ChatColor.Red
|
||||
end
|
||||
end
|
||||
|
||||
function styleChoices(tone)
|
||||
for i, obj in pairs(choices) do
|
||||
resetColor(obj, tone)
|
||||
end
|
||||
resetColor(lastChoice, tone)
|
||||
end
|
||||
|
||||
function styleMainFrame(tone)
|
||||
if tone == Enum.DialogTone.Neutral then
|
||||
mainFrame.Style = Enum.FrameStyle.ChatBlue
|
||||
mainFrame.Tail.Image = "rbxasset://textures/chatBubble_botBlue_tailRight.png"
|
||||
elseif tone == Enum.DialogTone.Friendly then
|
||||
mainFrame.Style = Enum.FrameStyle.ChatGreen
|
||||
mainFrame.Tail.Image = "rbxasset://textures/chatBubble_botGreen_tailRight.png"
|
||||
elseif tone == Enum.DialogTone.Enemy then
|
||||
mainFrame.Style = Enum.FrameStyle.ChatRed
|
||||
mainFrame.Tail.Image = "rbxasset://textures/chatBubble_botRed_tailRight.png"
|
||||
end
|
||||
|
||||
styleChoices(tone)
|
||||
end
|
||||
function setChatNotificationTone(gui, purpose, tone)
|
||||
if tone == Enum.DialogTone.Neutral then
|
||||
gui.Image.Image = "rbxasset://textures/chatBubble_botBlue_notify_bkg.png"
|
||||
elseif tone == Enum.DialogTone.Friendly then
|
||||
gui.Image.Image = "rbxasset://textures/chatBubble_botGreen_notify_bkg.png"
|
||||
elseif tone == Enum.DialogTone.Enemy then
|
||||
gui.Image.Image = "rbxasset://textures/chatBubble_botRed_notify_bkg.png"
|
||||
end
|
||||
if purpose == Enum.DialogPurpose.Quest then
|
||||
gui.Image.Button.Image = "rbxasset://textures/chatBubble_bot_notify_bang.png"
|
||||
elseif purpose == Enum.DialogPurpose.Help then
|
||||
gui.Image.Button.Image = "rbxasset://textures/chatBubble_bot_notify_question.png"
|
||||
elseif purpose == Enum.DialogPurpose.Shop then
|
||||
gui.Image.Button.Image = "rbxasset://textures/chatBubble_bot_notify_money.png"
|
||||
end
|
||||
end
|
||||
|
||||
function createMessageDialog()
|
||||
messageDialog = Instance.new("Frame");
|
||||
messageDialog.Name = "DialogScriptMessage"
|
||||
messageDialog.Style = Enum.FrameStyle.RobloxRound
|
||||
messageDialog.Visible = false
|
||||
|
||||
local text = Instance.new("TextLabel")
|
||||
text.Name = "Text"
|
||||
text.Position = UDim2.new(0,0,0,-1)
|
||||
text.Size = UDim2.new(1,0,1,0)
|
||||
text.FontSize = Enum.FontSize.Size14
|
||||
text.BackgroundTransparency = 1
|
||||
text.TextColor3 = Color3.new(1,1,1)
|
||||
text.RobloxLocked = true
|
||||
text.Parent = messageDialog
|
||||
end
|
||||
|
||||
function showMessage(msg, size)
|
||||
messageDialog.Text.Text = msg
|
||||
messageDialog.Size = UDim2.new(0,size,0,40)
|
||||
messageDialog.Position = UDim2.new(0.5, -size/2, 0.5, -40)
|
||||
messageDialog.Visible = true
|
||||
wait(2)
|
||||
messageDialog.Visible = false
|
||||
end
|
||||
|
||||
function variableDelay(str)
|
||||
local length = math.min(string.len(str), 100)
|
||||
wait(0.75 + ((length/75) * 1.5))
|
||||
end
|
||||
|
||||
function resetColor(frame, tone)
|
||||
if tone == Enum.DialogTone.Neutral then
|
||||
frame.BackgroundColor3 = Color3.new(0/255, 0/255, 179/255)
|
||||
frame.Number.TextColor3 = Color3.new(45/255, 142/255, 245/255)
|
||||
elseif tone == Enum.DialogTone.Friendly then
|
||||
frame.BackgroundColor3 = Color3.new(0/255, 77/255, 0/255)
|
||||
frame.Number.TextColor3 = Color3.new(0/255, 190/255, 0/255)
|
||||
elseif tone == Enum.DialogTone.Enemy then
|
||||
frame.BackgroundColor3 = Color3.new(140/255, 0/255, 0/255)
|
||||
frame.Number.TextColor3 = Color3.new(255/255,88/255, 79/255)
|
||||
end
|
||||
end
|
||||
|
||||
function highlightColor(frame, tone)
|
||||
if tone == Enum.DialogTone.Neutral then
|
||||
frame.BackgroundColor3 = Color3.new(2/255, 108/255, 255/255)
|
||||
frame.Number.TextColor3 = Color3.new(1, 1, 1)
|
||||
elseif tone == Enum.DialogTone.Friendly then
|
||||
frame.BackgroundColor3 = Color3.new(0/255, 128/255, 0/255)
|
||||
frame.Number.TextColor3 = Color3.new(1, 1, 1)
|
||||
elseif tone == Enum.DialogTone.Enemy then
|
||||
frame.BackgroundColor3 = Color3.new(204/255, 0/255, 0/255)
|
||||
frame.Number.TextColor3 = Color3.new(1, 1, 1)
|
||||
end
|
||||
end
|
||||
|
||||
function wanderDialog()
|
||||
print("Wander")
|
||||
mainFrame.Visible = false
|
||||
endDialog()
|
||||
showMessage(characterWanderedOffMessage, characterWanderedOffSize)
|
||||
end
|
||||
|
||||
function timeoutDialog()
|
||||
print("Timeout")
|
||||
mainFrame.Visible = false
|
||||
endDialog()
|
||||
showMessage(conversationTimedOut, conversationTimedOutSize)
|
||||
end
|
||||
function normalEndDialog()
|
||||
print("Done")
|
||||
endDialog()
|
||||
end
|
||||
|
||||
function endDialog()
|
||||
if currentAbortDialogScript then
|
||||
currentAbortDialogScript:Remove()
|
||||
currentAbortDialogScript = nil
|
||||
end
|
||||
|
||||
local dialog = currentConversationDialog
|
||||
currentConversationDialog = nil
|
||||
if dialog and dialog.InUse then
|
||||
local reenableScript = reenableDialogScript:Clone()
|
||||
reenableScript.archivable = false
|
||||
reenableScript.Disabled = false
|
||||
reenableScript.Parent = dialog
|
||||
end
|
||||
|
||||
for dialog, gui in pairs(dialogMap) do
|
||||
if dialog and gui then
|
||||
gui.Enabled = not dialog.InUse
|
||||
end
|
||||
end
|
||||
|
||||
currentConversationPartner = nil
|
||||
end
|
||||
|
||||
function sanitizeMessage(msg)
|
||||
if string.len(msg) == 0 then
|
||||
return "..."
|
||||
else
|
||||
return msg
|
||||
end
|
||||
end
|
||||
|
||||
function selectChoice(choice)
|
||||
renewKillswitch(currentConversationDialog)
|
||||
|
||||
--First hide the Gui
|
||||
mainFrame.Visible = false
|
||||
if choice == lastChoice then
|
||||
game.Chat:Chat(game.Players.LocalPlayer.Character, "Goodbye!", getChatColor(currentTone()))
|
||||
|
||||
normalEndDialog()
|
||||
else
|
||||
local dialogChoice = choiceMap[choice]
|
||||
|
||||
game.Chat:Chat(game.Players.LocalPlayer.Character, sanitizeMessage(dialogChoice.UserDialog), getChatColor(currentTone()))
|
||||
wait(1)
|
||||
currentConversationDialog:SignalDialogChoiceSelected(player, dialogChoice)
|
||||
game.Chat:Chat(currentConversationPartner, sanitizeMessage(dialogChoice.ResponseDialog), getChatColor(currentTone()))
|
||||
|
||||
variableDelay(dialogChoice.ResponseDialog)
|
||||
presentDialogChoices(currentConversationPartner, dialogChoice:GetChildren())
|
||||
end
|
||||
end
|
||||
|
||||
function newChoice(numberText)
|
||||
local frame = Instance.new("TextButton")
|
||||
frame.BackgroundColor3 = Color3.new(0/255, 0/255, 179/255)
|
||||
frame.AutoButtonColor = false
|
||||
frame.BorderSizePixel = 0
|
||||
frame.Text = ""
|
||||
frame.MouseEnter:connect(function() highlightColor(frame, currentTone()) end)
|
||||
frame.MouseLeave:connect(function() resetColor(frame, currentTone()) end)
|
||||
frame.MouseButton1Click:connect(function() selectChoice(frame) end)
|
||||
frame.RobloxLocked = true
|
||||
|
||||
local number = Instance.new("TextLabel")
|
||||
number.Name = "Number"
|
||||
number.TextColor3 = Color3.new(127/255, 212/255, 255/255)
|
||||
number.Text = numberText
|
||||
number.FontSize = Enum.FontSize.Size14
|
||||
number.BackgroundTransparency = 1
|
||||
number.Position = UDim2.new(0,4,0,2)
|
||||
number.Size = UDim2.new(0,20,0,24)
|
||||
number.TextXAlignment = Enum.TextXAlignment.Left
|
||||
number.TextYAlignment = Enum.TextYAlignment.Top
|
||||
number.RobloxLocked = true
|
||||
number.Parent = frame
|
||||
|
||||
local prompt = Instance.new("TextLabel")
|
||||
prompt.Name = "UserPrompt"
|
||||
prompt.BackgroundTransparency = 1
|
||||
prompt.TextColor3 = Color3.new(1,1,1)
|
||||
prompt.FontSize = Enum.FontSize.Size14
|
||||
prompt.Position = UDim2.new(0,28, 0, 2)
|
||||
prompt.Size = UDim2.new(1,-32, 1, -4)
|
||||
prompt.TextXAlignment = Enum.TextXAlignment.Left
|
||||
prompt.TextYAlignment = Enum.TextYAlignment.Top
|
||||
prompt.TextWrap = true
|
||||
prompt.RobloxLocked = true
|
||||
prompt.Parent = frame
|
||||
|
||||
return frame
|
||||
end
|
||||
function initialize(parent)
|
||||
choices[1] = newChoice("1)")
|
||||
choices[2] = newChoice("2)")
|
||||
choices[3] = newChoice("3)")
|
||||
choices[4] = newChoice("4)")
|
||||
|
||||
lastChoice = newChoice("5)")
|
||||
lastChoice.UserPrompt.Text = "Goodbye!"
|
||||
lastChoice.Size = UDim2.new(1,0,0,28)
|
||||
|
||||
mainFrame = Instance.new("Frame")
|
||||
mainFrame.Name = "UserDialogArea"
|
||||
mainFrame.Size = UDim2.new(0, 350, 0, 200)
|
||||
mainFrame.Style = Enum.FrameStyle.ChatBlue
|
||||
mainFrame.Visible = false
|
||||
|
||||
imageLabel = Instance.new("ImageLabel")
|
||||
imageLabel.Name = "Tail"
|
||||
imageLabel.Size = UDim2.new(0,62,0,53)
|
||||
imageLabel.Position = UDim2.new(1,8,0.25)
|
||||
imageLabel.Image = "rbxasset://textures/chatBubble_botBlue_tailRight.png"
|
||||
imageLabel.BackgroundTransparency = 1
|
||||
imageLabel.RobloxLocked = true
|
||||
imageLabel.Parent = mainFrame
|
||||
|
||||
for n, obj in pairs(choices) do
|
||||
obj.RobloxLocked = true
|
||||
obj.Parent = mainFrame
|
||||
end
|
||||
lastChoice.RobloxLocked = true
|
||||
lastChoice.Parent = mainFrame
|
||||
|
||||
mainFrame.RobloxLocked = true
|
||||
mainFrame.Parent = parent
|
||||
end
|
||||
|
||||
function presentDialogChoices(talkingPart, dialogChoices)
|
||||
if not currentConversationDialog then
|
||||
return
|
||||
end
|
||||
|
||||
currentConversationPartner = talkingPart
|
||||
sortedDialogChoices = {}
|
||||
for n, obj in pairs(dialogChoices) do
|
||||
if obj:IsA("DialogChoice") then
|
||||
table.insert(sortedDialogChoices, obj)
|
||||
end
|
||||
end
|
||||
table.sort(sortedDialogChoices, function(a,b) return a.Name < b.Name end)
|
||||
|
||||
if #sortedDialogChoices == 0 then
|
||||
normalEndDialog()
|
||||
return
|
||||
end
|
||||
|
||||
local pos = 1
|
||||
local yPosition = 0
|
||||
choiceMap = {}
|
||||
for n, obj in pairs(choices) do
|
||||
obj.Visible = false
|
||||
end
|
||||
|
||||
for n, obj in pairs(sortedDialogChoices) do
|
||||
if pos <= #choices then
|
||||
--3 lines is the maximum, set it to that temporarily
|
||||
choices[pos].Size = UDim2.new(1, 0, 0, 24*3)
|
||||
choices[pos].UserPrompt.Text = obj.UserDialog
|
||||
local height = math.ceil(choices[pos].UserPrompt.TextBounds.Y/24)*24
|
||||
|
||||
choices[pos].Position = UDim2.new(0, 0, 0, yPosition)
|
||||
choices[pos].Size = UDim2.new(1, 0, 0, height)
|
||||
choices[pos].Visible = true
|
||||
|
||||
choiceMap[choices[pos]] = obj
|
||||
|
||||
yPosition = yPosition + height
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
lastChoice.Position = UDim2.new(0,0,0,yPosition)
|
||||
lastChoice.Number.Text = pos .. ")"
|
||||
|
||||
mainFrame.Size = UDim2.new(0, 350, 0, yPosition+24+32)
|
||||
mainFrame.Position = UDim2.new(0,20,0.0, -mainFrame.Size.Y.Offset-20)
|
||||
styleMainFrame(currentTone())
|
||||
mainFrame.Visible = true
|
||||
end
|
||||
|
||||
function doDialog(dialog)
|
||||
while not Instance.Lock(dialog, player) do
|
||||
wait()
|
||||
end
|
||||
|
||||
if dialog.InUse then
|
||||
Instance.Unlock(dialog)
|
||||
return
|
||||
else
|
||||
dialog.InUse = true
|
||||
Instance.Unlock(dialog)
|
||||
end
|
||||
|
||||
currentConversationDialog = dialog
|
||||
game.Chat:Chat(dialog.Parent, dialog.InitialPrompt, getChatColor(dialog.Tone))
|
||||
variableDelay(dialog.InitialPrompt)
|
||||
|
||||
presentDialogChoices(dialog.Parent, dialog:GetChildren())
|
||||
end
|
||||
|
||||
function renewKillswitch(dialog)
|
||||
if currentAbortDialogScript then
|
||||
currentAbortDialogScript:Remove()
|
||||
currentAbortDialogScript = nil
|
||||
end
|
||||
|
||||
currentAbortDialogScript = timeoutScript:Clone()
|
||||
currentAbortDialogScript.archivable = false
|
||||
currentAbortDialogScript.Disabled = false
|
||||
currentAbortDialogScript.Parent = dialog
|
||||
end
|
||||
|
||||
function checkForLeaveArea()
|
||||
while currentConversationDialog do
|
||||
if currentConversationDialog.Parent and (player:DistanceFromCharacter(currentConversationDialog.Parent.Position) >= currentConversationDialog.ConversationDistance) then
|
||||
wanderDialog()
|
||||
end
|
||||
wait(1)
|
||||
end
|
||||
end
|
||||
|
||||
function startDialog(dialog)
|
||||
if dialog.Parent and dialog.Parent:IsA("BasePart") then
|
||||
if player:DistanceFromCharacter(dialog.Parent.Position) >= dialog.ConversationDistance then
|
||||
showMessage(tooFarAwayMessage, tooFarAwaySize)
|
||||
return
|
||||
end
|
||||
|
||||
for dialog, gui in pairs(dialogMap) do
|
||||
if dialog and gui then
|
||||
gui.Enabled = false
|
||||
end
|
||||
end
|
||||
|
||||
renewKillswitch(dialog)
|
||||
|
||||
delay(1, checkForLeaveArea)
|
||||
doDialog(dialog)
|
||||
end
|
||||
end
|
||||
|
||||
function removeDialog(dialog)
|
||||
if dialogMap[dialog] then
|
||||
dialogMap[dialog]:Remove()
|
||||
dialogMap[dialog] = nil
|
||||
end
|
||||
if dialogConnections[dialog] then
|
||||
dialogConnections[dialog]:disconnect()
|
||||
dialogConnections[dialog] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function addDialog(dialog)
|
||||
if dialog.Parent then
|
||||
if dialog.Parent:IsA("BasePart") then
|
||||
local chatGui = chatNotificationGui:clone()
|
||||
chatGui.Enabled = not dialog.InUse
|
||||
chatGui.Adornee = dialog.Parent
|
||||
chatGui.RobloxLocked = true
|
||||
chatGui.Parent = game.CoreGui
|
||||
chatGui.Image.Button.MouseButton1Click:connect(function() startDialog(dialog) end)
|
||||
setChatNotificationTone(chatGui, dialog.Purpose, dialog.Tone)
|
||||
|
||||
dialogMap[dialog] = chatGui
|
||||
|
||||
dialogConnections[dialog] = dialog.Changed:connect(function(prop)
|
||||
if prop == "Parent" and dialog.Parent then
|
||||
--This handles the reparenting case, seperate from removal case
|
||||
removeDialog(dialog)
|
||||
addDialog(dialog)
|
||||
elseif prop == "InUse" then
|
||||
chatGui.Enabled = not currentConversationDialog and not dialog.InUse
|
||||
if dialog == currentConversationDialog then
|
||||
timeoutDialog()
|
||||
end
|
||||
elseif prop == "Tone" or prop == "Purpose" then
|
||||
setChatNotificationTone(chatGui, dialog.Purpose, dialog.Tone)
|
||||
end
|
||||
end)
|
||||
else -- still need to listen to parent changes even if current parent is not a BasePart
|
||||
dialogConnections[dialog] = dialog.Changed:connect(function(prop)
|
||||
if prop == "Parent" and dialog.Parent then
|
||||
--This handles the reparenting case, seperate from removal case
|
||||
removeDialog(dialog)
|
||||
addDialog(dialog)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function fetchScripts()
|
||||
local model = game:GetService("InsertService"):LoadAsset(39226062)
|
||||
if type(model) == "string" then -- load failed, lets try again
|
||||
wait(0.1)
|
||||
model = game:GetService("InsertService"):LoadAsset(39226062)
|
||||
end
|
||||
if type(model) == "string" then -- not going to work, lets bail
|
||||
return
|
||||
end
|
||||
|
||||
waitForChild(model,"TimeoutScript")
|
||||
timeoutScript = model.TimeoutScript
|
||||
waitForChild(model,"ReenableDialogScript")
|
||||
reenableDialogScript = model.ReenableDialogScript
|
||||
end
|
||||
|
||||
function onLoad()
|
||||
waitForProperty(game.Players, "LocalPlayer")
|
||||
player = game.Players.LocalPlayer
|
||||
waitForProperty(player, "Character")
|
||||
|
||||
--print("Fetching Scripts")
|
||||
fetchScripts()
|
||||
|
||||
--print("Creating Guis")
|
||||
createChatNotificationGui()
|
||||
|
||||
--print("Creating MessageDialog")
|
||||
createMessageDialog()
|
||||
messageDialog.RobloxLocked = true
|
||||
messageDialog.Parent = gui
|
||||
|
||||
--print("Waiting for BottomLeftControl")
|
||||
waitForChild(gui, "BottomLeftControl")
|
||||
|
||||
--print("Initializing Frame")
|
||||
local frame = Instance.new("Frame")
|
||||
frame.Name = "DialogFrame"
|
||||
frame.Position = UDim2.new(0,0,0,0)
|
||||
frame.Size = UDim2.new(0,0,0,0)
|
||||
frame.BackgroundTransparency = 1
|
||||
frame.RobloxLocked = true
|
||||
frame.Parent = gui.BottomLeftControl
|
||||
initialize(frame)
|
||||
|
||||
--print("Adding Dialogs")
|
||||
game.CollectionService.ItemAdded:connect(function(obj) if obj:IsA("Dialog") then addDialog(obj) end end)
|
||||
game.CollectionService.ItemRemoved:connect(function(obj) if obj:IsA("Dialog") then removeDialog(obj) end end)
|
||||
for i, obj in pairs(game.CollectionService:GetCollection("Dialog")) do
|
||||
if obj:IsA("Dialog") then
|
||||
addDialog(obj)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
onLoad()
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
--rbxassetid%862%
|
||||
--build our gui
|
||||
|
||||
local popupFrame = Instance.new("Frame")
|
||||
popupFrame.Position = UDim2.new(0.5,-165,0.5,-175)
|
||||
popupFrame.Size = UDim2.new(0,330,0,350)
|
||||
popupFrame.Style = Enum.FrameStyle.DropShadow
|
||||
popupFrame.ZIndex = 4
|
||||
popupFrame.Name = "Popup"
|
||||
popupFrame.Visible = false
|
||||
popupFrame.Parent = script.Parent
|
||||
|
||||
local darken = popupFrame:clone()
|
||||
darken.Size = UDim2.new(1,16,1,16)
|
||||
darken.Position = UDim2.new(0,-8,0,-8)
|
||||
darken.Name = "Darken"
|
||||
darken.ZIndex = 1
|
||||
darken.Parent = popupFrame
|
||||
|
||||
local acceptButton = Instance.new("TextButton")
|
||||
acceptButton.Position = UDim2.new(0,20,0,270)
|
||||
acceptButton.Size = UDim2.new(0,100,0,50)
|
||||
acceptButton.Font = Enum.Font.ArialBold
|
||||
acceptButton.FontSize = Enum.FontSize.Size24
|
||||
acceptButton.Style = Enum.ButtonStyle.RobloxRoundButton
|
||||
acceptButton.TextColor3 = Color3.new(248/255,248/255,248/255)
|
||||
acceptButton.Text = "Yes"
|
||||
acceptButton.ZIndex = 5
|
||||
acceptButton.Name = "AcceptButton"
|
||||
acceptButton.Parent = popupFrame
|
||||
|
||||
local declineButton = acceptButton:clone()
|
||||
declineButton.Position = UDim2.new(1,-120,0,270)
|
||||
declineButton.Text = "No"
|
||||
declineButton.Name = "DeclineButton"
|
||||
declineButton.Parent = popupFrame
|
||||
|
||||
local okButton = acceptButton:clone()
|
||||
okButton.Name = "OKButton"
|
||||
okButton.Text = "OK"
|
||||
okButton.Position = UDim2.new(0.5,-50,0,270)
|
||||
okButton.Visible = false
|
||||
okButton.Parent = popupFrame
|
||||
|
||||
local popupImage = Instance.new("ImageLabel")
|
||||
popupImage.BackgroundTransparency = 1
|
||||
popupImage.Position = UDim2.new(0.5,-140,0,10)
|
||||
popupImage.Size = UDim2.new(0,280,0,280)
|
||||
popupImage.ZIndex = 3
|
||||
popupImage.Name = "PopupImage"
|
||||
popupImage.Parent = popupFrame
|
||||
|
||||
local backing = Instance.new("ImageLabel")
|
||||
backing.BackgroundTransparency = 1
|
||||
backing.Size = UDim2.new(1,0,1,0)
|
||||
backing.Image = "http://www.mete0r.xyz/asset/?id=47574181"
|
||||
backing.Name = "Backing"
|
||||
backing.ZIndex = 2
|
||||
backing.Parent = popupImage
|
||||
|
||||
local popupText = Instance.new("TextLabel")
|
||||
popupText.Name = "PopupText"
|
||||
popupText.Size = UDim2.new(1,0,0.8,0)
|
||||
popupText.Font = Enum.Font.ArialBold
|
||||
popupText.FontSize = Enum.FontSize.Size36
|
||||
popupText.BackgroundTransparency = 1
|
||||
popupText.Text = "Hello I'm a popup"
|
||||
popupText.TextColor3 = Color3.new(248/255,248/255,248/255)
|
||||
popupText.TextWrap = true
|
||||
popupText.ZIndex = 5
|
||||
popupText.Parent = popupFrame
|
||||
|
||||
script:remove()
|
||||
|
|
@ -0,0 +1,307 @@
|
|||
--rbxassetid%863%
|
||||
function waitForProperty(instance, property)
|
||||
while not instance[property] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
function waitForChild(instance, name)
|
||||
while not instance:FindFirstChild(name) do
|
||||
instance.ChildAdded:wait()
|
||||
end
|
||||
end
|
||||
|
||||
waitForProperty(game.Players,"LocalPlayer")
|
||||
waitForChild(script.Parent,"Popup")
|
||||
waitForChild(script.Parent.Popup,"AcceptButton")
|
||||
script.Parent.Popup.AcceptButton.Modal = true
|
||||
|
||||
local localPlayer = game.Players.LocalPlayer
|
||||
local teleportUI = nil
|
||||
|
||||
local acceptedTeleport = Instance.new("IntValue")
|
||||
|
||||
local friendRequestBlacklist = {}
|
||||
|
||||
local teleportEnabled = true
|
||||
|
||||
local makePopupInvisible = function()
|
||||
if script.Parent.Popup then script.Parent.Popup.Visible = false end
|
||||
end
|
||||
|
||||
function makeFriend(fromPlayer,toPlayer)
|
||||
|
||||
local popup = script.Parent:FindFirstChild("Popup")
|
||||
if popup == nil then return end -- there is no popup!
|
||||
if popup.Visible then return end -- currently popping something, abort!
|
||||
if friendRequestBlacklist[fromPlayer] then return end -- previously cancelled friend request, we don't want it!
|
||||
|
||||
popup.PopupText.Text = "Accept Friend Request from " .. tostring(fromPlayer.Name) .. "?"
|
||||
popup.PopupImage.Image = "http://www.mete0r.xyz/thumbs/avatar.ashx?userId="..tostring(fromPlayer.userId).."&x=352&y=352"
|
||||
|
||||
showTwoButtons()
|
||||
popup.Visible = true
|
||||
popup.AcceptButton.Text = "Accept"
|
||||
popup.DeclineButton.Text = "Decline"
|
||||
popup:TweenSize(UDim2.new(0,330,0,350),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true)
|
||||
|
||||
local yesCon, noCon
|
||||
|
||||
yesCon = popup.AcceptButton.MouseButton1Click:connect(function()
|
||||
popup.Visible = false
|
||||
toPlayer:RequestFriendship(fromPlayer)
|
||||
if yesCon then yesCon:disconnect() end
|
||||
if noCon then noCon:disconnect() end
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end)
|
||||
|
||||
noCon = popup.DeclineButton.MouseButton1Click:connect(function()
|
||||
popup.Visible = false
|
||||
toPlayer:RevokeFriendship(fromPlayer)
|
||||
friendRequestBlacklist[fromPlayer] = true
|
||||
print("pop up blacklist")
|
||||
if yesCon then yesCon:disconnect() end
|
||||
if noCon then noCon:disconnect() end
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
game.Players.FriendRequestEvent:connect(function(fromPlayer,toPlayer,event)
|
||||
|
||||
-- if this doesn't involve me, then do nothing
|
||||
if fromPlayer ~= localPlayer and toPlayer ~= localPlayer then return end
|
||||
|
||||
if fromPlayer == localPlayer then
|
||||
if event == Enum.FriendRequestEvent.Accept then
|
||||
game:GetService("GuiService"):SendNotification("You are Friends",
|
||||
"With " .. toPlayer.Name .. "!",
|
||||
"http://www.mete0r.xyz/thumbs/avatar.ashx?userId="..tostring(toPlayer.userId).."&x=48&y=48",
|
||||
5,
|
||||
function()
|
||||
|
||||
end)
|
||||
end
|
||||
elseif toPlayer == localPlayer then
|
||||
if event == Enum.FriendRequestEvent.Issue then
|
||||
if friendRequestBlacklist[fromPlayer] then return end -- previously cancelled friend request, we don't want it!
|
||||
game:GetService("GuiService"):SendNotification("Friend Request",
|
||||
"From " .. fromPlayer.Name,
|
||||
"http://www.mete0r.xyz/thumbs/avatar.ashx?userId="..tostring(fromPlayer.userId).."&x=48&y=48",
|
||||
8,
|
||||
function()
|
||||
makeFriend(fromPlayer,toPlayer)
|
||||
end)
|
||||
elseif event == Enum.FriendRequestEvent.Accept then
|
||||
game:GetService("GuiService"):SendNotification("You are Friends",
|
||||
"With " .. fromPlayer.Name .. "!",
|
||||
"http://www.mete0r.xyz/thumbs/avatar.ashx?userId="..tostring(fromPlayer.userId).."&x=48&y=48",
|
||||
5,
|
||||
function()
|
||||
|
||||
end)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
function showOneButton()
|
||||
local popup = script.Parent:FindFirstChild("Popup")
|
||||
if popup then
|
||||
popup.OKButton.Visible = true
|
||||
popup.DeclineButton.Visible = false
|
||||
popup.AcceptButton.Visible = false
|
||||
end
|
||||
end
|
||||
|
||||
function showTwoButtons()
|
||||
local popup = script.Parent:FindFirstChild("Popup")
|
||||
if popup then
|
||||
popup.OKButton.Visible = false
|
||||
popup.DeclineButton.Visible = true
|
||||
popup.AcceptButton.Visible = true
|
||||
end
|
||||
end
|
||||
|
||||
function onTeleport(teleportState, placeId, spawnName)
|
||||
if game:GetService("TeleportService").CustomizedTeleportUI == false then
|
||||
if teleportState == Enum.TeleportState.Started then
|
||||
showTeleportUI("Teleport started...", 0)
|
||||
elseif teleportState == Enum.TeleportState.WaitingForServer then
|
||||
showTeleportUI("Requesting server...", 0)
|
||||
elseif teleportState == Enum.TeleportState.InProgress then
|
||||
showTeleportUI("Teleporting...", 0)
|
||||
elseif teleportState == Enum.TeleportState.Failed then
|
||||
showTeleportUI("Teleport failed. Insufficient privileges or target place does not exist.", 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function showTeleportUI(message, timer)
|
||||
if teleportUI ~= nil then
|
||||
teleportUI:Remove()
|
||||
end
|
||||
waitForChild(localPlayer, "PlayerGui")
|
||||
teleportUI = Instance.new("Message", localPlayer.PlayerGui)
|
||||
teleportUI.Text = message
|
||||
if timer > 0 then
|
||||
wait(timer)
|
||||
teleportUI:Remove()
|
||||
end
|
||||
end
|
||||
|
||||
if teleportEnabled then
|
||||
|
||||
localPlayer.OnTeleport:connect(onTeleport)
|
||||
|
||||
game:GetService("TeleportService").ErrorCallback = function(message)
|
||||
local popup = script.Parent:FindFirstChild("Popup")
|
||||
showOneButton()
|
||||
popup.PopupText.Text = message
|
||||
local clickCon
|
||||
clickCon = popup.OKButton.MouseButton1Click:connect(function()
|
||||
game:GetService("TeleportService"):TeleportCancel()
|
||||
if clickCon then clickCon:disconnect() end
|
||||
game.GuiService:RemoveCenterDialog(script.Parent:FindFirstChild("Popup"))
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end)
|
||||
game.GuiService:AddCenterDialog(script.Parent:FindFirstChild("Popup"), Enum.CenterDialogType.QuitDialog,
|
||||
--ShowFunction
|
||||
function()
|
||||
showOneButton()
|
||||
script.Parent:FindFirstChild("Popup").Visible = true
|
||||
popup:TweenSize(UDim2.new(0,330,0,350),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true)
|
||||
end,
|
||||
--HideFunction
|
||||
function()
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end)
|
||||
|
||||
end
|
||||
game:GetService("TeleportService").ConfirmationCallback = function(message, placeId, spawnName)
|
||||
local popup = script.Parent:FindFirstChild("Popup")
|
||||
popup.PopupText.Text = message
|
||||
popup.PopupImage.Image = ""
|
||||
|
||||
local yesCon, noCon
|
||||
|
||||
local function killCons()
|
||||
if yesCon then yesCon:disconnect() end
|
||||
if noCon then noCon:disconnect() end
|
||||
game.GuiService:RemoveCenterDialog(script.Parent:FindFirstChild("Popup"))
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end
|
||||
|
||||
yesCon = popup.AcceptButton.MouseButton1Click:connect(function()
|
||||
killCons()
|
||||
local success, err = pcall(function() game:GetService("TeleportService"):TeleportImpl(placeId,spawnName) end)
|
||||
if not success then
|
||||
showOneButton()
|
||||
popup.PopupText.Text = err
|
||||
local clickCon
|
||||
clickCon = popup.OKButton.MouseButton1Click:connect(function()
|
||||
if clickCon then clickCon:disconnect() end
|
||||
game.GuiService:RemoveCenterDialog(script.Parent:FindFirstChild("Popup"))
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end)
|
||||
game.GuiService:AddCenterDialog(script.Parent:FindFirstChild("Popup"), Enum.CenterDialogType.QuitDialog,
|
||||
--ShowFunction
|
||||
function()
|
||||
showOneButton()
|
||||
script.Parent:FindFirstChild("Popup").Visible = true
|
||||
popup:TweenSize(UDim2.new(0,330,0,350),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true)
|
||||
end,
|
||||
--HideFunction
|
||||
function()
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
||||
noCon = popup.DeclineButton.MouseButton1Click:connect(function()
|
||||
killCons()
|
||||
local success = pcall(function() game:GetService("TeleportService"):TeleportCancel() end)
|
||||
end)
|
||||
|
||||
local centerDialogSuccess = pcall(function() game.GuiService:AddCenterDialog(script.Parent:FindFirstChild("Popup"), Enum.CenterDialogType.QuitDialog,
|
||||
--ShowFunction
|
||||
function()
|
||||
showTwoButtons()
|
||||
popup.AcceptButton.Text = "Leave"
|
||||
popup.DeclineButton.Text = "Stay"
|
||||
script.Parent:FindFirstChild("Popup").Visible = true
|
||||
popup:TweenSize(UDim2.new(0,330,0,350),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true)
|
||||
end,
|
||||
--HideFunction
|
||||
function()
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end)
|
||||
end)
|
||||
|
||||
if centerDialogSuccess == false then
|
||||
script.Parent:FindFirstChild("Popup").Visible = true
|
||||
popup.AcceptButton.Text = "Leave"
|
||||
popup.DeclineButton.Text = "Stay"
|
||||
popup:TweenSize(UDim2.new(0,330,0,350),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true)
|
||||
end
|
||||
return true
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
game:GetService("MarketplaceService").ClientLuaDialogRequested:connect(function(message, accept, decline)
|
||||
local popup = script.Parent:FindFirstChild("Popup")
|
||||
popup.PopupText.Text = message
|
||||
popup.PopupImage.Image = ""
|
||||
|
||||
local yesCon, noCon
|
||||
|
||||
local function killCons()
|
||||
if yesCon then yesCon:disconnect() end
|
||||
if noCon then noCon:disconnect() end
|
||||
game.GuiService:RemoveCenterDialog(script.Parent:FindFirstChild("Popup"))
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end
|
||||
|
||||
yesCon = popup.AcceptButton.MouseButton1Click:connect(function()
|
||||
killCons()
|
||||
game:GetService("MarketplaceService"):SignalServerLuaDialogClosed(true);
|
||||
end)
|
||||
|
||||
noCon = popup.DeclineButton.MouseButton1Click:connect(function()
|
||||
killCons()
|
||||
game:GetService("MarketplaceService"):SignalServerLuaDialogClosed(false);
|
||||
end)
|
||||
|
||||
local centerDialogSuccess = pcall(function() game.GuiService:AddCenterDialog(script.Parent:FindFirstChild("Popup"), Enum.CenterDialogType.QuitDialog,
|
||||
function()
|
||||
showTwoButtons()
|
||||
popup.AcceptButton.Text = accept
|
||||
popup.DeclineButton.Text = decline
|
||||
script.Parent:FindFirstChild("Popup").Visible = true
|
||||
popup:TweenSize(UDim2.new(0,330,0,350),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true)
|
||||
end,
|
||||
function()
|
||||
popup:TweenSize(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true,makePopupInvisible())
|
||||
end)
|
||||
end)
|
||||
|
||||
if centerDialogSuccess == false then
|
||||
script.Parent:FindFirstChild("Popup").Visible = true
|
||||
popup.AcceptButton.Text = accept
|
||||
popup.DeclineButton.Text = decline
|
||||
popup:TweenSize(UDim2.new(0,330,0,350),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,1,true)
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end)
|
||||
|
||||
Game:GetService("PointsService").PointsAwarded:connect( function(userId, pointsAwarded, userBalanceInGame, userTotalBalance)
|
||||
if userId == Game.Players.LocalPlayer.userId then
|
||||
game:GetService("GuiService"):SendNotification("Points Awarded!",
|
||||
"You received " ..tostring(pointsAwarded) .. " points!",
|
||||
"http://www.mete0r.xyz/asset?id=155363793",
|
||||
5,
|
||||
function()
|
||||
end)
|
||||
end
|
||||
end)
|
||||
|
|
@ -0,0 +1,317 @@
|
|||
--rbxassetid%866%
|
||||
--[[
|
||||
This script controls the gui the player sees in regards to his or her health.
|
||||
Can be turned with Game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health,false)
|
||||
Copyright ROBLOX 2014. Written by Ben Tkacheff.
|
||||
--]]
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Initialize/Variables
|
||||
while not Game do
|
||||
wait(1/60)
|
||||
end
|
||||
while not Game.Players do
|
||||
wait(1/60)
|
||||
end
|
||||
|
||||
local useCoreHealthBar = false
|
||||
local success = pcall(function() useCoreHealthBar = Game.Players:GetUseCoreScriptHealthBar() end)
|
||||
if not success or not useCoreHealthBar then
|
||||
return
|
||||
end
|
||||
|
||||
local currentHumanoid = nil
|
||||
|
||||
local HealthGui = nil
|
||||
local lastHealth = 100
|
||||
local HealthPercentageForOverlay = 5
|
||||
local maxBarTweenTime = 0.3
|
||||
local greenColor = Color3.new(0.2, 1, 0.2)
|
||||
local redColor = Color3.new(1, 0.2, 0.2)
|
||||
local yellowColor = Color3.new(1, 1, 0.2)
|
||||
|
||||
local guiEnabled = false
|
||||
local healthChangedConnection = nil
|
||||
local humanoidDiedConnection = nil
|
||||
local characterAddedConnection = nil
|
||||
|
||||
local greenBarImage = "rbxasset://textures/ui/Health-BKG-Center.png"
|
||||
local greenBarImageLeft = "rbxasset://textures/ui/Health-BKG-Left-Cap.png"
|
||||
local greenBarImageRight = "rbxasset://textures/ui/Health-BKG-Right-Cap.png"
|
||||
local hurtOverlayImage = "http://www.mete0r.xyz/asset/?id=34854607"
|
||||
|
||||
Game:GetService("ContentProvider"):Preload(greenBarImage)
|
||||
Game:GetService("ContentProvider"):Preload(hurtOverlayImage)
|
||||
|
||||
while not Game.Players.LocalPlayer do
|
||||
wait(1/60)
|
||||
end
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Functions
|
||||
|
||||
local capHeight = 15
|
||||
local capWidth = 7
|
||||
|
||||
function CreateGui()
|
||||
if HealthGui and #HealthGui:GetChildren() > 0 then
|
||||
HealthGui.Parent = Game.CoreGui.RobloxGui
|
||||
return
|
||||
end
|
||||
|
||||
local hurtOverlay = Instance.new("ImageLabel")
|
||||
hurtOverlay.Name = "HurtOverlay"
|
||||
hurtOverlay.BackgroundTransparency = 1
|
||||
hurtOverlay.Image = hurtOverlayImage
|
||||
hurtOverlay.Position = UDim2.new(-10,0,-10,0)
|
||||
hurtOverlay.Size = UDim2.new(20,0,20,0)
|
||||
hurtOverlay.Visible = false
|
||||
hurtOverlay.Parent = HealthGui
|
||||
|
||||
local healthFrame = Instance.new("Frame")
|
||||
healthFrame.Name = "HealthFrame"
|
||||
healthFrame.BackgroundTransparency = 1
|
||||
healthFrame.BackgroundColor3 = Color3.new(1,1,1)
|
||||
healthFrame.BorderColor3 = Color3.new(0,0,0)
|
||||
healthFrame.BorderSizePixel = 0
|
||||
healthFrame.Position = UDim2.new(0.5,-85,1,-20)
|
||||
healthFrame.Size = UDim2.new(0,170,0,capHeight)
|
||||
healthFrame.Parent = HealthGui
|
||||
|
||||
|
||||
local healthBarBackCenter = Instance.new("ImageLabel")
|
||||
healthBarBackCenter.Name = "healthBarBackCenter"
|
||||
healthBarBackCenter.BackgroundTransparency = 1
|
||||
healthBarBackCenter.Image = greenBarImage
|
||||
healthBarBackCenter.Size = UDim2.new(1,-capWidth*2,1,0)
|
||||
healthBarBackCenter.Position = UDim2.new(0,capWidth,0,0)
|
||||
healthBarBackCenter.Parent = healthFrame
|
||||
healthBarBackCenter.ImageColor3 = Color3.new(1,1,1)
|
||||
|
||||
local healthBarBackLeft = Instance.new("ImageLabel")
|
||||
healthBarBackLeft.Name = "healthBarBackLeft"
|
||||
healthBarBackLeft.BackgroundTransparency = 1
|
||||
healthBarBackLeft.Image = greenBarImageLeft
|
||||
healthBarBackLeft.Size = UDim2.new(0,capWidth,1,0)
|
||||
healthBarBackLeft.Position = UDim2.new(0,0,0,0)
|
||||
healthBarBackLeft.Parent = healthFrame
|
||||
healthBarBackLeft.ImageColor3 = Color3.new(1,1,1)
|
||||
|
||||
local healthBarBackRight = Instance.new("ImageLabel")
|
||||
healthBarBackRight.Name = "healthBarBackRight"
|
||||
healthBarBackRight.BackgroundTransparency = 1
|
||||
healthBarBackRight.Image = greenBarImageRight
|
||||
healthBarBackRight.Size = UDim2.new(0,capWidth,1,0)
|
||||
healthBarBackRight.Position = UDim2.new(1,-capWidth,0,0)
|
||||
healthBarBackRight.Parent = healthFrame
|
||||
healthBarBackRight.ImageColor3 = Color3.new(1,1,1)
|
||||
|
||||
|
||||
local healthBar = Instance.new("Frame")
|
||||
healthBar.Name = "HealthBar"
|
||||
healthBar.BackgroundTransparency = 1
|
||||
healthBar.BackgroundColor3 = Color3.new(1,1,1)
|
||||
healthBar.BorderColor3 = Color3.new(0,0,0)
|
||||
healthBar.BorderSizePixel = 0
|
||||
healthBar.ClipsDescendants = true
|
||||
healthBar.Position = UDim2.new(0, 0, 0, 0)
|
||||
healthBar.Size = UDim2.new(1,0,1,0)
|
||||
healthBar.Parent = healthFrame
|
||||
|
||||
|
||||
local healthBarCenter = Instance.new("ImageLabel")
|
||||
healthBarCenter.Name = "healthBarCenter"
|
||||
healthBarCenter.BackgroundTransparency = 1
|
||||
healthBarCenter.Image = greenBarImage
|
||||
healthBarCenter.Size = UDim2.new(1,-capWidth*2,1,0)
|
||||
healthBarCenter.Position = UDim2.new(0,capWidth,0,0)
|
||||
healthBarCenter.Parent = healthBar
|
||||
healthBarCenter.ImageColor3 = greenColor
|
||||
|
||||
local healthBarLeft = Instance.new("ImageLabel")
|
||||
healthBarLeft.Name = "healthBarLeft"
|
||||
healthBarLeft.BackgroundTransparency = 1
|
||||
healthBarLeft.Image = greenBarImageLeft
|
||||
healthBarLeft.Size = UDim2.new(0,capWidth,1,0)
|
||||
healthBarLeft.Position = UDim2.new(0,0,0,0)
|
||||
healthBarLeft.Parent = healthBar
|
||||
healthBarLeft.ImageColor3 = greenColor
|
||||
|
||||
local healthBarRight = Instance.new("ImageLabel")
|
||||
healthBarRight.Name = "healthBarRight"
|
||||
healthBarRight.BackgroundTransparency = 1
|
||||
healthBarRight.Image = greenBarImageRight
|
||||
healthBarRight.Size = UDim2.new(0,capWidth,1,0)
|
||||
healthBarRight.Position = UDim2.new(1,-capWidth,0,0)
|
||||
healthBarRight.Parent = healthBar
|
||||
healthBarRight.ImageColor3 = greenColor
|
||||
|
||||
HealthGui.Parent = Game.CoreGui.RobloxGui
|
||||
end
|
||||
|
||||
function UpdateGui(health)
|
||||
if not HealthGui then return end
|
||||
|
||||
local healthFrame = HealthGui:FindFirstChild("HealthFrame")
|
||||
if not healthFrame then return end
|
||||
|
||||
local healthBar = healthFrame:FindFirstChild("HealthBar")
|
||||
if not healthBar then return end
|
||||
|
||||
-- If more than 1/4 health, bar = green. Else, bar = red.
|
||||
local percentHealth = (health/currentHumanoid.MaxHealth)
|
||||
if percentHealth ~= percentHealth then
|
||||
percentHealth = 1
|
||||
healthBar.healthBarCenter.ImageColor3 = yellowColor
|
||||
healthBar.healthBarRight.ImageColor3 = yellowColor
|
||||
healthBar.healthBarLeft.ImageColor3 = yellowColor
|
||||
elseif percentHealth > 0.25 then
|
||||
healthBar.healthBarCenter.ImageColor3 = greenColor
|
||||
healthBar.healthBarRight.ImageColor3 = greenColor
|
||||
healthBar.healthBarLeft.ImageColor3 = greenColor
|
||||
else
|
||||
healthBar.healthBarCenter.ImageColor3 = redColor
|
||||
healthBar.healthBarRight.ImageColor3 = redColor
|
||||
healthBar.healthBarLeft.ImageColor3 = redColor
|
||||
end
|
||||
|
||||
local width = (health / currentHumanoid.MaxHealth)
|
||||
width = math.max(math.min(width,1),0) -- make sure width is between 0 and 1
|
||||
if width ~= width then width = 1 end
|
||||
|
||||
local healthDelta = lastHealth - health
|
||||
lastHealth = health
|
||||
|
||||
local percentOfTotalHealth = math.abs(healthDelta/currentHumanoid.MaxHealth)
|
||||
percentOfTotalHealth = math.max(math.min(percentOfTotalHealth,1),0) -- make sure percentOfTotalHealth is between 0 and 1
|
||||
if percentOfTotalHealth ~= percentOfTotalHealth then percentOfTotalHealth = 1 end
|
||||
|
||||
local newHealthSize = UDim2.new(width,0,1,0)
|
||||
|
||||
healthBar.Size = newHealthSize
|
||||
|
||||
local sizeX = healthBar.AbsoluteSize.X
|
||||
if sizeX < capWidth then
|
||||
healthBar.healthBarCenter.Visible = false
|
||||
healthBar.healthBarRight.Visible = false
|
||||
elseif sizeX < (2*capWidth + 1) then
|
||||
healthBar.healthBarCenter.Visible = true
|
||||
healthBar.healthBarCenter.Size = UDim2.new(0,sizeX - capWidth,1,0)
|
||||
healthBar.healthBarRight.Visible = false
|
||||
else
|
||||
healthBar.healthBarCenter.Visible = true
|
||||
healthBar.healthBarCenter.Size = UDim2.new(1,-capWidth*2,1,0)
|
||||
healthBar.healthBarRight.Visible = true
|
||||
end
|
||||
|
||||
local thresholdForHurtOverlay = currentHumanoid.MaxHealth * (HealthPercentageForOverlay/100)
|
||||
|
||||
if healthDelta >= thresholdForHurtOverlay then
|
||||
AnimateHurtOverlay()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function AnimateHurtOverlay()
|
||||
if not HealthGui then return end
|
||||
|
||||
local overlay = HealthGui:FindFirstChild("HurtOverlay")
|
||||
if not overlay then return end
|
||||
|
||||
local newSize = UDim2.new(20, 0, 20, 0)
|
||||
local newPos = UDim2.new(-10, 0, -10, 0)
|
||||
|
||||
if overlay:IsDescendantOf(Game) then
|
||||
-- stop any tweens on overlay
|
||||
overlay:TweenSizeAndPosition(newSize,newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Linear,0,true,function()
|
||||
|
||||
-- show the gui
|
||||
overlay.Size = UDim2.new(1,0,1,0)
|
||||
overlay.Position = UDim2.new(0,0,0,0)
|
||||
overlay.Visible = true
|
||||
|
||||
-- now tween the hide
|
||||
if overlay:IsDescendantOf(Game) then
|
||||
overlay:TweenSizeAndPosition(newSize,newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,10,false,function()
|
||||
overlay.Visible = false
|
||||
end)
|
||||
else
|
||||
overlay.Size = newSize
|
||||
overlay.Position = newPos
|
||||
end
|
||||
end)
|
||||
else
|
||||
overlay.Size = newSize
|
||||
overlay.Position = newPos
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function humanoidDied()
|
||||
UpdateGui(0)
|
||||
end
|
||||
|
||||
function disconnectPlayerConnections()
|
||||
if characterAddedConnection then characterAddedConnection:disconnect() end
|
||||
if humanoidDiedConnection then humanoidDiedConnection:disconnect() end
|
||||
if healthChangedConnection then healthChangedConnection:disconnect() end
|
||||
end
|
||||
|
||||
function newPlayerCharacter()
|
||||
disconnectPlayerConnections()
|
||||
startGui()
|
||||
end
|
||||
|
||||
function startGui()
|
||||
characterAddedConnection = Game.Players.LocalPlayer.CharacterAdded:connect(newPlayerCharacter)
|
||||
|
||||
local character = Game.Players.LocalPlayer.Character
|
||||
if not character then
|
||||
return
|
||||
end
|
||||
|
||||
currentHumanoid = character:WaitForChild("Humanoid")
|
||||
if not currentHumanoid then
|
||||
return
|
||||
end
|
||||
|
||||
if not Game.StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Health) then
|
||||
return
|
||||
end
|
||||
|
||||
healthChangedConnection = currentHumanoid.HealthChanged:connect(UpdateGui)
|
||||
humanoidDiedConnection = currentHumanoid.Died:connect(humanoidDied)
|
||||
UpdateGui(currentHumanoid.Health)
|
||||
|
||||
CreateGui()
|
||||
end
|
||||
|
||||
|
||||
|
||||
---------------------------------------------------------------------
|
||||
-- Start Script
|
||||
|
||||
HealthGui = Instance.new("Frame")
|
||||
HealthGui.Name = "HealthGui"
|
||||
HealthGui.BackgroundTransparency = 1
|
||||
HealthGui.Size = UDim2.new(1,0,1,0)
|
||||
|
||||
Game.StarterGui.CoreGuiChangedSignal:connect(function(coreGuiType,enabled)
|
||||
if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then
|
||||
if guiEnabled and not enabled then
|
||||
if HealthGui then
|
||||
HealthGui.Parent = nil
|
||||
end
|
||||
disconnectPlayerConnections()
|
||||
elseif not guiEnabled and enabled then
|
||||
startGui()
|
||||
end
|
||||
|
||||
guiEnabled = enabled
|
||||
end
|
||||
end)
|
||||
|
||||
if Game.StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Health) then
|
||||
guiEnabled = true
|
||||
startGui()
|
||||
end
|
||||
|
|
@ -0,0 +1,869 @@
|
|||
--rbxassetid%868%
|
||||
-- This script creates almost all gui elements found in the backpack (warning: there are a lot!)
|
||||
-- TODO: automate this process
|
||||
|
||||
if game.CoreGui.Version < 3 then return end -- peace out if we aren't using the right client
|
||||
|
||||
local gui = script.Parent
|
||||
|
||||
-- A couple of necessary functions
|
||||
local function waitForChild(instance, name)
|
||||
while not instance:FindFirstChild(name) do
|
||||
instance.ChildAdded:wait()
|
||||
end
|
||||
end
|
||||
local function waitForProperty(instance, property)
|
||||
while not instance[property] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
|
||||
local function IsTouchDevice()
|
||||
return Game:GetService('UserInputService').TouchEnabled
|
||||
end
|
||||
|
||||
local function IsPhone()
|
||||
if Game:GetService("GuiService"):GetScreenResolution().Y <= 500 and IsTouchDevice() then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
waitForChild(game,"Players")
|
||||
waitForProperty(game.Players,"LocalPlayer")
|
||||
local player = game.Players.LocalPlayer
|
||||
|
||||
-- First up is the current loadout
|
||||
local CurrentLoadout = Instance.new("Frame")
|
||||
CurrentLoadout.Name = "CurrentLoadout"
|
||||
CurrentLoadout.Position = UDim2.new(0.5, -300, 1, -85)
|
||||
CurrentLoadout.Size = UDim2.new(0, 600, 0, 54)
|
||||
CurrentLoadout.BackgroundTransparency = 1
|
||||
CurrentLoadout.RobloxLocked = true
|
||||
CurrentLoadout.Parent = gui
|
||||
|
||||
local CLBackground = Instance.new('ImageLabel')
|
||||
CLBackground.Name = 'Background';
|
||||
CLBackground.Size = UDim2.new(1.2, 0, 1.2, 0);
|
||||
CLBackground.Image = "http://www.mete0r.xyz/asset/?id=96536002"
|
||||
CLBackground.BackgroundTransparency = 1.0;
|
||||
CLBackground.Position = UDim2.new(-0.1, 0, -0.1, 0);
|
||||
CLBackground.ZIndex = 0.0;
|
||||
CLBackground.Parent = CurrentLoadout
|
||||
CLBackground.Visible = false
|
||||
|
||||
local Debounce = Instance.new("BoolValue")
|
||||
Debounce.Name = "Debounce"
|
||||
Debounce.RobloxLocked = true
|
||||
Debounce.Parent = CurrentLoadout
|
||||
|
||||
local BackpackButton = Instance.new("ImageButton")
|
||||
BackpackButton.RobloxLocked = true
|
||||
BackpackButton.Visible = false
|
||||
BackpackButton.Name = "BackpackButton"
|
||||
BackpackButton.BackgroundTransparency = 1
|
||||
BackpackButton.Image = "rbxasset://textures/ui/Backpack_Open.png"
|
||||
BackpackButton.Position = UDim2.new(0.5, -7, 1, -55)
|
||||
BackpackButton.Size = UDim2.new(0, 14, 0, 9)
|
||||
waitForChild(gui,"ControlFrame")
|
||||
BackpackButton.Parent = gui.ControlFrame
|
||||
|
||||
local NumSlots = 9
|
||||
|
||||
if IsPhone() then
|
||||
NumSlots = 3
|
||||
CurrentLoadout.Size = UDim2.new(0,180,0,54)
|
||||
CurrentLoadout.Position = UDim2.new(0.5,-90,1,-85)
|
||||
end
|
||||
|
||||
for i = 0, NumSlots do
|
||||
local slotFrame = Instance.new("Frame")
|
||||
slotFrame.RobloxLocked = true
|
||||
slotFrame.BackgroundColor3 = Color3.new(0,0,0)
|
||||
slotFrame.BackgroundTransparency = 1
|
||||
slotFrame.BorderColor3 = Color3.new(1, 1, 1)
|
||||
slotFrame.BorderSizePixel = 0
|
||||
slotFrame.Name = "Slot" .. tostring(i)
|
||||
slotFrame.ZIndex = 4.0
|
||||
if i == 0 then
|
||||
slotFrame.Position = UDim2.new(0.9, 48, 0, 0)
|
||||
else
|
||||
slotFrame.Position = UDim2.new((i - 1) * 0.1, (i-1)* 6,0,0)
|
||||
end
|
||||
|
||||
|
||||
slotFrame.Size = UDim2.new(0, 54, 1, 0)
|
||||
slotFrame.Parent = CurrentLoadout
|
||||
|
||||
if gui.AbsoluteSize.Y <= 320 then
|
||||
slotFrame.Position = UDim2.new(0, (i-1)* 60, 0, -50)
|
||||
end
|
||||
if gui.AbsoluteSize.Y <= 320 and i == 0 then
|
||||
slotFrame:Destroy()
|
||||
end
|
||||
end
|
||||
|
||||
local TempSlot = Instance.new("ImageButton")
|
||||
TempSlot.Name = "TempSlot"
|
||||
TempSlot.Active = true
|
||||
TempSlot.Size = UDim2.new(1,0,1,0)
|
||||
TempSlot.BackgroundTransparency = 1.0
|
||||
TempSlot.Style = 'Custom'
|
||||
TempSlot.Visible = false
|
||||
TempSlot.RobloxLocked = true
|
||||
TempSlot.Parent = CurrentLoadout
|
||||
TempSlot.ZIndex = 3.0
|
||||
|
||||
local slotBackground = Instance.new('Frame')
|
||||
slotBackground.Name = 'Background'
|
||||
slotBackground.BackgroundTransparency = 1.0
|
||||
slotBackground.Style = "DropShadow"
|
||||
slotBackground.Position = UDim2.new(0, -10, 0, -10)
|
||||
slotBackground.Size = UDim2.new(1, 20, 1, 20)
|
||||
slotBackground.Parent = TempSlot
|
||||
|
||||
local HighLight = Instance.new('ImageLabel')
|
||||
HighLight.Name = 'Highlight'
|
||||
HighLight.BackgroundTransparency = 1.0
|
||||
HighLight.Image = 'http://www.mete0r.xyz/asset/?id=97643886'
|
||||
HighLight.Size = UDim2.new(1, 0, 1, 0)
|
||||
--HighLight.Parent = TempSlot
|
||||
HighLight.Visible = false
|
||||
|
||||
-- TempSlot Children
|
||||
local GearReference = Instance.new("ObjectValue")
|
||||
GearReference.Name = "GearReference"
|
||||
GearReference.RobloxLocked = true
|
||||
GearReference.Parent = TempSlot
|
||||
|
||||
|
||||
local ToolTipLabel = Instance.new("TextLabel")
|
||||
ToolTipLabel.Name = "ToolTipLabel"
|
||||
ToolTipLabel.RobloxLocked = true
|
||||
ToolTipLabel.Text = ""
|
||||
ToolTipLabel.BackgroundTransparency = 0.5
|
||||
ToolTipLabel.BorderSizePixel = 0
|
||||
ToolTipLabel.Visible = false
|
||||
ToolTipLabel.TextColor3 = Color3.new(1,1,1)
|
||||
ToolTipLabel.BackgroundColor3 = Color3.new(0,0,0)
|
||||
ToolTipLabel.TextStrokeTransparency = 0
|
||||
ToolTipLabel.Font = Enum.Font.ArialBold
|
||||
ToolTipLabel.FontSize = Enum.FontSize.Size14
|
||||
--ToolTipLabel.TextWrap = true
|
||||
ToolTipLabel.Size = UDim2.new(1,60,0,20)
|
||||
ToolTipLabel.Position = UDim2.new(0,-30,0,-30)
|
||||
ToolTipLabel.Parent = TempSlot
|
||||
|
||||
|
||||
local Kill = Instance.new("BoolValue")
|
||||
Kill.Name = "Kill"
|
||||
Kill.RobloxLocked = true
|
||||
Kill.Parent = TempSlot
|
||||
|
||||
local GearImage = Instance.new("ImageLabel")
|
||||
GearImage.Name = "GearImage"
|
||||
GearImage.BackgroundTransparency = 1
|
||||
GearImage.Position = UDim2.new(0, 0, 0, 0)
|
||||
GearImage.Size = UDim2.new(1, 0, 1, 0)
|
||||
GearImage.ZIndex = 5.0
|
||||
GearImage.RobloxLocked = true
|
||||
GearImage.Parent = TempSlot
|
||||
|
||||
local SlotNumber = Instance.new("TextLabel")
|
||||
SlotNumber.Name = "SlotNumber"
|
||||
SlotNumber.BackgroundTransparency = 1
|
||||
SlotNumber.BorderSizePixel = 0
|
||||
SlotNumber.Font = Enum.Font.ArialBold
|
||||
SlotNumber.FontSize = Enum.FontSize.Size18
|
||||
SlotNumber.Position = UDim2.new(0, 0, 0, 0)
|
||||
SlotNumber.Size = UDim2.new(0,10,0,15)
|
||||
SlotNumber.TextColor3 = Color3.new(1,1,1)
|
||||
SlotNumber.TextTransparency = 0
|
||||
SlotNumber.TextXAlignment = Enum.TextXAlignment.Left
|
||||
SlotNumber.TextYAlignment = Enum.TextYAlignment.Bottom
|
||||
SlotNumber.RobloxLocked = true
|
||||
SlotNumber.Parent = TempSlot
|
||||
SlotNumber.ZIndex = 5
|
||||
|
||||
if IsTouchDevice() then
|
||||
SlotNumber.Visible = false
|
||||
end
|
||||
|
||||
local SlotNumberDownShadow = SlotNumber:Clone()
|
||||
SlotNumberDownShadow.Name = "SlotNumberDownShadow"
|
||||
SlotNumberDownShadow.TextColor3 = Color3.new(0,0,0)
|
||||
SlotNumberDownShadow.Position = UDim2.new(0, 1, 0, -1)
|
||||
SlotNumberDownShadow.Parent = TempSlot
|
||||
SlotNumberDownShadow.ZIndex = 2
|
||||
|
||||
local SlotNumberUpShadow = SlotNumberDownShadow:Clone()
|
||||
SlotNumberUpShadow.Name = "SlotNumberUpShadow"
|
||||
SlotNumberUpShadow.Position = UDim2.new(0, -1, 0, -1)
|
||||
SlotNumberUpShadow.Parent = TempSlot
|
||||
|
||||
local GearText = Instance.new("TextLabel")
|
||||
GearText.RobloxLocked = true
|
||||
GearText.Name = "GearText"
|
||||
GearText.BackgroundTransparency = 1
|
||||
GearText.Font = Enum.Font.Arial
|
||||
GearText.FontSize = Enum.FontSize.Size14
|
||||
GearText.Position = UDim2.new(0,-8,0,-8)
|
||||
GearText.Size = UDim2.new(1,16,1,16)
|
||||
GearText.Text = ""
|
||||
GearText.TextColor3 = Color3.new(1,1,1)
|
||||
GearText.TextWrap = true
|
||||
GearText.Parent = TempSlot
|
||||
GearText.ZIndex = 5.0
|
||||
|
||||
--- Great, now lets make the inventory!
|
||||
|
||||
local Backpack = Instance.new("Frame")
|
||||
Backpack.RobloxLocked = true
|
||||
Backpack.Visible = false
|
||||
Backpack.Name = "Backpack"
|
||||
Backpack.Position = UDim2.new(0.5, 0, 0.5, 0)
|
||||
Backpack.BackgroundColor3 = Color3.new(32/255, 32/255, 32/255)
|
||||
Backpack.BackgroundTransparency = 0.5
|
||||
Backpack.BorderSizePixel = 0
|
||||
Backpack.Parent = gui
|
||||
Backpack.Active = true
|
||||
|
||||
-- Backpack Children
|
||||
local SwapSlot = Instance.new("BoolValue")
|
||||
SwapSlot.RobloxLocked = true
|
||||
SwapSlot.Name = "SwapSlot"
|
||||
SwapSlot.Parent = Backpack
|
||||
|
||||
-- SwapSlot Children
|
||||
local Slot = Instance.new("IntValue")
|
||||
Slot.RobloxLocked = true
|
||||
Slot.Name = "Slot"
|
||||
Slot.Parent = SwapSlot
|
||||
|
||||
local GearButton = Instance.new("ObjectValue")
|
||||
GearButton.RobloxLocked = true
|
||||
GearButton.Name = "GearButton"
|
||||
GearButton.Parent = SwapSlot
|
||||
|
||||
local Tabs = Instance.new("Frame")
|
||||
Tabs.Name = "Tabs"
|
||||
Tabs.Visible = false
|
||||
Tabs.Active = false
|
||||
Tabs.RobloxLocked = true
|
||||
Tabs.BackgroundColor3 = Color3.new(0,0,0)
|
||||
Tabs.BackgroundTransparency = 0.08
|
||||
Tabs.BorderSizePixel = 0
|
||||
Tabs.Position = UDim2.new(0,0,-0.1,-4)
|
||||
Tabs.Size = UDim2.new(1,0,0.1,4)
|
||||
Tabs.Parent = Backpack
|
||||
|
||||
-- Tabs Children
|
||||
|
||||
local tabLine = Instance.new("Frame")
|
||||
tabLine.RobloxLocked = true
|
||||
tabLine.Name = "TabLine"
|
||||
tabLine.BackgroundColor3 = Color3.new(53/255, 53/255, 53/255)
|
||||
tabLine.BorderSizePixel = 0
|
||||
tabLine.Position = UDim2.new(0,5,1,-4)
|
||||
tabLine.Size = UDim2.new(1,-10,0,4)
|
||||
tabLine.ZIndex = 2
|
||||
tabLine.Parent = Tabs
|
||||
|
||||
local InventoryButton = Instance.new("TextButton")
|
||||
InventoryButton.RobloxLocked = true
|
||||
InventoryButton.Name = "InventoryButton"
|
||||
InventoryButton.Size = UDim2.new(0,60,0,30)
|
||||
InventoryButton.Position = UDim2.new(0,7,1,-31)
|
||||
InventoryButton.BackgroundColor3 = Color3.new(1,1,1)
|
||||
InventoryButton.BorderColor3 = Color3.new(1,1,1)
|
||||
InventoryButton.Font = Enum.Font.ArialBold
|
||||
InventoryButton.FontSize = Enum.FontSize.Size18
|
||||
InventoryButton.Text = "Gear"
|
||||
InventoryButton.AutoButtonColor = false
|
||||
InventoryButton.TextColor3 = Color3.new(0,0,0)
|
||||
InventoryButton.Selected = true
|
||||
InventoryButton.Active = true
|
||||
InventoryButton.ZIndex = 3
|
||||
InventoryButton.Parent = Tabs
|
||||
|
||||
if game.CoreGui.Version >= 8 then
|
||||
local WardrobeButton = Instance.new("TextButton")
|
||||
WardrobeButton.RobloxLocked = true
|
||||
WardrobeButton.Name = "WardrobeButton"
|
||||
WardrobeButton.Size = UDim2.new(0,90,0,30)
|
||||
WardrobeButton.Position = UDim2.new(0,77,1,-31)
|
||||
WardrobeButton.BackgroundColor3 = Color3.new(0,0,0)
|
||||
WardrobeButton.BorderColor3 = Color3.new(1,1,1)
|
||||
WardrobeButton.Font = Enum.Font.ArialBold
|
||||
WardrobeButton.FontSize = Enum.FontSize.Size18
|
||||
WardrobeButton.Text = "Wardrobe"
|
||||
WardrobeButton.AutoButtonColor = false
|
||||
WardrobeButton.TextColor3 = Color3.new(1,1,1)
|
||||
WardrobeButton.Selected = false
|
||||
WardrobeButton.Active = true
|
||||
WardrobeButton.Parent = Tabs
|
||||
end
|
||||
|
||||
local closeButton = Instance.new("TextButton")
|
||||
closeButton.RobloxLocked = true
|
||||
closeButton.Name = "CloseButton"
|
||||
closeButton.Font = Enum.Font.ArialBold
|
||||
closeButton.FontSize = Enum.FontSize.Size24
|
||||
closeButton.Position = UDim2.new(1,-33,0,4)
|
||||
closeButton.Size = UDim2.new(0,30,0,30)
|
||||
closeButton.Style = Enum.ButtonStyle.RobloxButton
|
||||
closeButton.Text = ""
|
||||
closeButton.TextColor3 = Color3.new(1,1,1)
|
||||
closeButton.Parent = Tabs
|
||||
closeButton.Modal = true
|
||||
|
||||
--closeButton child
|
||||
local XImage = Instance.new("ImageLabel")
|
||||
XImage.RobloxLocked = true
|
||||
XImage.Name = "XImage"
|
||||
game:GetService("ContentProvider"):Preload("http://www.mete0r.xyz/asset/?id=75547445")
|
||||
XImage.Image = "http://www.mete0r.xyz/asset/?id=75547445" --TODO: move to rbxasset
|
||||
XImage.BackgroundTransparency = 1
|
||||
XImage.Position = UDim2.new(-.25,-1,-.25,-1)
|
||||
XImage.Size = UDim2.new(1.5,2,1.5,2)
|
||||
XImage.ZIndex = 2
|
||||
XImage.Parent = closeButton
|
||||
|
||||
-- Generic Search gui used across backpack
|
||||
local SearchFrame = Instance.new("Frame")
|
||||
SearchFrame.RobloxLocked = true
|
||||
SearchFrame.Name = "SearchFrame"
|
||||
SearchFrame.BackgroundTransparency = 1
|
||||
SearchFrame.Position = UDim2.new(1,-220,0,2)
|
||||
SearchFrame.Size = UDim2.new(0,220,0,24)
|
||||
SearchFrame.Parent = Backpack
|
||||
|
||||
-- SearchFrame Children
|
||||
local SearchButton = Instance.new("ImageButton")
|
||||
SearchButton.RobloxLocked = true
|
||||
SearchButton.Name = "SearchButton"
|
||||
SearchButton.Size = UDim2.new(0,25,0,25)
|
||||
SearchButton.BackgroundTransparency = 1
|
||||
SearchButton.Image = "rbxasset://textures/ui/SearchIcon.png"
|
||||
SearchButton.Parent = SearchFrame
|
||||
|
||||
local SearchBoxFrame = Instance.new("TextButton")
|
||||
SearchBoxFrame.RobloxLocked = true
|
||||
SearchBoxFrame.Position = UDim2.new(0,25,0,-2)
|
||||
SearchBoxFrame.Size = UDim2.new(1,-28,0,30)
|
||||
SearchBoxFrame.Name = "SearchBoxFrame"
|
||||
SearchBoxFrame.Text = ""
|
||||
SearchBoxFrame.Style = Enum.ButtonStyle.RobloxRoundButton
|
||||
SearchBoxFrame.Parent = SearchFrame
|
||||
|
||||
-- SearchBoxFrame Children
|
||||
local SearchBox = Instance.new("TextBox")
|
||||
SearchBox.RobloxLocked = true
|
||||
SearchBox.Name = "SearchBox"
|
||||
SearchBox.BackgroundTransparency = 1
|
||||
SearchBox.Font = Enum.Font.ArialBold
|
||||
SearchBox.FontSize = Enum.FontSize.Size12
|
||||
SearchBox.Position = UDim2.new(0,-5,0,-5)
|
||||
SearchBox.Size = UDim2.new(1,10,1,10)
|
||||
SearchBox.TextColor3 = Color3.new(1,1,1)
|
||||
SearchBox.TextXAlignment = Enum.TextXAlignment.Left
|
||||
SearchBox.ZIndex = 2
|
||||
SearchBox.TextWrap = true
|
||||
SearchBox.Text = "Search..."
|
||||
SearchBox.Parent = SearchBoxFrame
|
||||
|
||||
|
||||
local ResetButton = Instance.new("TextButton")
|
||||
ResetButton.RobloxLocked = true
|
||||
ResetButton.Visible = false
|
||||
ResetButton.Name = "ResetButton"
|
||||
ResetButton.Position = UDim2.new(1,-26,0,3)
|
||||
ResetButton.Size = UDim2.new(0,20,0,20)
|
||||
ResetButton.Style = Enum.ButtonStyle.RobloxButtonDefault
|
||||
ResetButton.Text = "X"
|
||||
ResetButton.TextColor3 = Color3.new(1,1,1)
|
||||
ResetButton.Font = Enum.Font.ArialBold
|
||||
ResetButton.FontSize = Enum.FontSize.Size18
|
||||
ResetButton.ZIndex = 3
|
||||
ResetButton.Parent = SearchFrame
|
||||
|
||||
------------------------------- GEAR -------------------------------------------------------
|
||||
local Gear = Instance.new("Frame")
|
||||
Gear.Name = "Gear"
|
||||
Gear.RobloxLocked = true
|
||||
Gear.BackgroundTransparency = 1
|
||||
Gear.Size = UDim2.new(1,0,1,0)
|
||||
Gear.ClipsDescendants = true
|
||||
Gear.Parent = Backpack
|
||||
|
||||
-- Gear Children
|
||||
local AssetsList = Instance.new("Frame")
|
||||
AssetsList.RobloxLocked = true
|
||||
AssetsList.Name = "AssetsList"
|
||||
AssetsList.BackgroundTransparency = 1
|
||||
AssetsList.Size = UDim2.new(0.2,0,1,0)
|
||||
AssetsList.Style = Enum.FrameStyle.RobloxSquare
|
||||
AssetsList.Visible = false
|
||||
AssetsList.Parent = Gear
|
||||
|
||||
local GearGrid = Instance.new("Frame")
|
||||
GearGrid.RobloxLocked = true
|
||||
GearGrid.Name = "GearGrid"
|
||||
GearGrid.Size = UDim2.new(0.95, 0, 1, 0)
|
||||
GearGrid.BackgroundTransparency = 1
|
||||
GearGrid.Parent = Gear
|
||||
|
||||
|
||||
local GearButton = Instance.new("ImageButton")
|
||||
GearButton.RobloxLocked = true
|
||||
GearButton.Visible = false
|
||||
GearButton.Name = "GearButton"
|
||||
GearButton.Size = UDim2.new(0, 54, 0, 54)
|
||||
GearButton.Style = 'Custom'
|
||||
GearButton.Parent = GearGrid
|
||||
GearButton.BackgroundTransparency = 1.0
|
||||
|
||||
local slotBackground = Instance.new('Frame')
|
||||
slotBackground.Name = 'Background'
|
||||
slotBackground.BackgroundTransparency = 1.0
|
||||
slotBackground.Size = UDim2.new(1, 16, 1, 16)
|
||||
slotBackground.Position = UDim2.new(0, -8, 0, -8)
|
||||
slotBackground.Parent = GearButton
|
||||
slotBackground.Style = "DropShadow"
|
||||
|
||||
|
||||
-- GearButton Children
|
||||
local GearReference = Instance.new("ObjectValue")
|
||||
GearReference.RobloxLocked = true
|
||||
GearReference.Name = "GearReference"
|
||||
GearReference.Parent = GearButton
|
||||
|
||||
local GreyOutButton = Instance.new("Frame")
|
||||
GreyOutButton.RobloxLocked = true
|
||||
GreyOutButton.Name = "GreyOutButton"
|
||||
GreyOutButton.BackgroundTransparency = 0.5
|
||||
GreyOutButton.Size = UDim2.new(1,0,1,0)
|
||||
GreyOutButton.Active = true
|
||||
GreyOutButton.Visible = false
|
||||
GreyOutButton.ZIndex = 3
|
||||
GreyOutButton.Parent = GearButton
|
||||
|
||||
local GearText = Instance.new("TextLabel")
|
||||
GearText.RobloxLocked = true
|
||||
GearText.Name = "GearText"
|
||||
GearText.BackgroundTransparency = 1
|
||||
GearText.Font = Enum.Font.Arial
|
||||
GearText.FontSize = Enum.FontSize.Size14
|
||||
GearText.Position = UDim2.new(0,-8,0,-8)
|
||||
GearText.Size = UDim2.new(1,16,1,16)
|
||||
GearText.Text = ""
|
||||
GearText.ZIndex = 2
|
||||
GearText.TextColor3 = Color3.new(1,1,1)
|
||||
GearText.TextWrap = true
|
||||
GearText.Parent = GearButton
|
||||
|
||||
local GearGridScrollingArea = Instance.new("Frame")
|
||||
GearGridScrollingArea.RobloxLocked = true
|
||||
GearGridScrollingArea.Name = "GearGridScrollingArea"
|
||||
GearGridScrollingArea.Position = UDim2.new(1, -19, 0, 35)
|
||||
GearGridScrollingArea.Size = UDim2.new(0, 17, 1, -45)
|
||||
GearGridScrollingArea.BackgroundTransparency = 1
|
||||
GearGridScrollingArea.Parent = Gear
|
||||
|
||||
local GearLoadouts = Instance.new("Frame")
|
||||
GearLoadouts.RobloxLocked = true
|
||||
GearLoadouts.Name = "GearLoadouts"
|
||||
GearLoadouts.BackgroundTransparency = 1
|
||||
GearLoadouts.Position = UDim2.new(0.7,23,0.5,1)
|
||||
GearLoadouts.Size = UDim2.new(0.3,-23,0.5,-1)
|
||||
GearLoadouts.Parent = Gear
|
||||
GearLoadouts.Visible = false
|
||||
|
||||
-- GearLoadouts Children
|
||||
local GearLoadoutsHeader = Instance.new("Frame")
|
||||
GearLoadoutsHeader.RobloxLocked = true
|
||||
GearLoadoutsHeader.Name = "GearLoadoutsHeader"
|
||||
GearLoadoutsHeader.BackgroundColor3 = Color3.new(0,0,0)
|
||||
GearLoadoutsHeader.BackgroundTransparency = 0.2
|
||||
GearLoadoutsHeader.BorderColor3 = Color3.new(1,0,0)
|
||||
GearLoadoutsHeader.Size = UDim2.new(1,2,0.15,-1)
|
||||
GearLoadoutsHeader.Parent = GearLoadouts
|
||||
|
||||
-- GearLoadoutsHeader Children
|
||||
local LoadoutsHeaderText = Instance.new("TextLabel")
|
||||
LoadoutsHeaderText.RobloxLocked = true
|
||||
LoadoutsHeaderText.Name = "LoadoutsHeaderText"
|
||||
LoadoutsHeaderText.BackgroundTransparency = 1
|
||||
LoadoutsHeaderText.Font = Enum.Font.ArialBold
|
||||
LoadoutsHeaderText.FontSize = Enum.FontSize.Size18
|
||||
LoadoutsHeaderText.Size = UDim2.new(1,0,1,0)
|
||||
LoadoutsHeaderText.Text = "Loadouts"
|
||||
LoadoutsHeaderText.TextColor3 = Color3.new(1,1,1)
|
||||
LoadoutsHeaderText.Parent = GearLoadoutsHeader
|
||||
|
||||
local GearLoadoutsScrollingArea = GearGridScrollingArea:clone()
|
||||
GearLoadoutsScrollingArea.RobloxLocked = true
|
||||
GearLoadoutsScrollingArea.Name = "GearLoadoutsScrollingArea"
|
||||
GearLoadoutsScrollingArea.Position = UDim2.new(1,-15,0.15,2)
|
||||
GearLoadoutsScrollingArea.Size = UDim2.new(0,17,0.85,-2)
|
||||
GearLoadoutsScrollingArea.Parent = GearLoadouts
|
||||
|
||||
local LoadoutsList = Instance.new("Frame")
|
||||
LoadoutsList.RobloxLocked = true
|
||||
LoadoutsList.Name = "LoadoutsList"
|
||||
LoadoutsList.Position = UDim2.new(0,0,0.15,2)
|
||||
LoadoutsList.Size = UDim2.new(1,-17,0.85,-2)
|
||||
LoadoutsList.Style = Enum.FrameStyle.RobloxSquare
|
||||
LoadoutsList.Parent = GearLoadouts
|
||||
|
||||
local GearPreview = Instance.new("Frame")
|
||||
GearPreview.RobloxLocked = true
|
||||
GearPreview.Name = "GearPreview"
|
||||
GearPreview.Position = UDim2.new(0.7,23,0,0)
|
||||
GearPreview.Size = UDim2.new(0.3,-28,0.5,-1)
|
||||
GearPreview.BackgroundTransparency = 1
|
||||
GearPreview.ZIndex = 7
|
||||
GearPreview.Parent = Gear
|
||||
|
||||
-- GearPreview Children
|
||||
local GearStats = Instance.new("Frame")
|
||||
GearStats.RobloxLocked = true
|
||||
GearStats.Name = "GearStats"
|
||||
GearStats.BackgroundTransparency = 1
|
||||
GearStats.Position = UDim2.new(0,0,0.75,0)
|
||||
GearStats.Size = UDim2.new(1,0,0.25,0)
|
||||
GearStats.ZIndex = 8
|
||||
GearStats.Parent = GearPreview
|
||||
|
||||
-- GearStats Children
|
||||
local GearName = Instance.new("TextLabel")
|
||||
GearName.RobloxLocked = true
|
||||
GearName.Name = "GearName"
|
||||
GearName.BackgroundTransparency = 1
|
||||
GearName.Font = Enum.Font.ArialBold
|
||||
GearName.FontSize = Enum.FontSize.Size18
|
||||
GearName.Position = UDim2.new(0,-3,0,0)
|
||||
GearName.Size = UDim2.new(1,6,1,5)
|
||||
GearName.Text = ""
|
||||
GearName.TextColor3 = Color3.new(1,1,1)
|
||||
GearName.TextWrap = true
|
||||
GearName.ZIndex = 9
|
||||
GearName.Parent = GearStats
|
||||
|
||||
local GearImage = Instance.new("ImageLabel")
|
||||
GearImage.RobloxLocked = true
|
||||
GearImage.Name = "GearImage"
|
||||
GearImage.Image = ""
|
||||
GearImage.BackgroundTransparency = 1
|
||||
GearImage.Position = UDim2.new(0.125,0,0,0)
|
||||
GearImage.Size = UDim2.new(0.75,0,0.75,0)
|
||||
GearImage.ZIndex = 8
|
||||
GearImage.Parent = GearPreview
|
||||
|
||||
--GearImage Children
|
||||
local GearIcons = Instance.new("Frame")
|
||||
GearIcons.BackgroundColor3 = Color3.new(0,0,0)
|
||||
GearIcons.BackgroundTransparency = 0.5
|
||||
GearIcons.BorderSizePixel = 0
|
||||
GearIcons.RobloxLocked = true
|
||||
GearIcons.Name = "GearIcons"
|
||||
GearIcons.Position = UDim2.new(0.4,2,0.85,-2)
|
||||
GearIcons.Size = UDim2.new(0.6,0,0.15,0)
|
||||
GearIcons.Visible = false
|
||||
GearIcons.ZIndex = 9
|
||||
GearIcons.Parent = GearImage
|
||||
|
||||
-- GearIcons Children
|
||||
local GenreImage = Instance.new("ImageLabel")
|
||||
GenreImage.RobloxLocked = true
|
||||
GenreImage.Name = "GenreImage"
|
||||
GenreImage.BackgroundColor3 = Color3.new(102/255,153/255,1)
|
||||
GenreImage.BackgroundTransparency = 0.5
|
||||
GenreImage.BorderSizePixel = 0
|
||||
GenreImage.Size = UDim2.new(0.25,0,1,0)
|
||||
GenreImage.Parent = GearIcons
|
||||
|
||||
local AttributeOneImage = GenreImage:clone()
|
||||
AttributeOneImage.RobloxLocked = true
|
||||
AttributeOneImage.Name = "AttributeOneImage"
|
||||
AttributeOneImage.BackgroundColor3 = Color3.new(1,51/255,0)
|
||||
AttributeOneImage.Position = UDim2.new(0.25,0,0,0)
|
||||
AttributeOneImage.Parent = GearIcons
|
||||
|
||||
local AttributeTwoImage = GenreImage:clone()
|
||||
AttributeTwoImage.RobloxLocked = true
|
||||
AttributeTwoImage.Name = "AttributeTwoImage"
|
||||
AttributeTwoImage.BackgroundColor3 = Color3.new(153/255,1,153/255)
|
||||
AttributeTwoImage.Position = UDim2.new(0.5,0,0,0)
|
||||
AttributeTwoImage.Parent = GearIcons
|
||||
|
||||
local AttributeThreeImage = GenreImage:clone()
|
||||
AttributeThreeImage.RobloxLocked = true
|
||||
AttributeThreeImage.Name = "AttributeThreeImage"
|
||||
AttributeThreeImage.BackgroundColor3 = Color3.new(0,0.5,0.5)
|
||||
AttributeThreeImage.Position = UDim2.new(0.75,0,0,0)
|
||||
AttributeThreeImage.Parent = GearIcons
|
||||
|
||||
------------------------------- WARDROBE -------------------------------------------------------
|
||||
if game.CoreGui.Version < 8 then
|
||||
-- no need for this to stick around, we aren't ready for wardrobe
|
||||
script:remove()
|
||||
return
|
||||
end
|
||||
|
||||
local function makeCharFrame(frameName, parent)
|
||||
local frame = Instance.new("Frame")
|
||||
frame.RobloxLocked = true
|
||||
frame.Size = UDim2.new(1,0,1,-70)
|
||||
frame.Position = UDim2.new(0,0,0,20)
|
||||
frame.Name = frameName
|
||||
frame.BackgroundTransparency = 1
|
||||
frame.Parent = parent
|
||||
frame.Visible = false
|
||||
return frame
|
||||
end
|
||||
local function makeZone( zoneName, image, size, position, parent )
|
||||
local zone = Instance.new("ImageLabel")
|
||||
zone.RobloxLocked = true
|
||||
zone.Name = zoneName
|
||||
zone.Image = image
|
||||
zone.Size = size
|
||||
zone.BackgroundTransparency = 1
|
||||
zone.Position = position
|
||||
zone.Parent = parent
|
||||
return zone
|
||||
end
|
||||
local function makeStyledButton( buttonName, size, position, parent, buttonStyle )
|
||||
local button = Instance.new("ImageButton")
|
||||
button.RobloxLocked = true
|
||||
button.Name = buttonName
|
||||
button.Size = size
|
||||
button.Position = position
|
||||
if buttonStyle then
|
||||
button.Style = buttonStyle
|
||||
else
|
||||
button.BackgroundColor3 = Color3.new(0,0,0)
|
||||
button.BorderColor3 = Color3.new(1,1,1)
|
||||
end
|
||||
button.Parent = parent
|
||||
return button
|
||||
end
|
||||
local function makeTextLabel( TextLabelName,text,position,parent )
|
||||
local label = Instance.new("TextLabel")
|
||||
label.RobloxLocked = true
|
||||
label.BackgroundTransparency = 1
|
||||
label.Size = UDim2.new(0,32,0,14)
|
||||
label.Name = TextLabelName
|
||||
label.Font = Enum.Font.Arial
|
||||
label.TextColor3 = Color3.new(1,1,1)
|
||||
label.FontSize = Enum.FontSize.Size14
|
||||
label.Text = text
|
||||
label.Position = position
|
||||
label.Parent = parent
|
||||
end
|
||||
|
||||
|
||||
local Wardrobe = Instance.new("Frame")
|
||||
Wardrobe.Name = "Wardrobe"
|
||||
Wardrobe.RobloxLocked = true
|
||||
Wardrobe.BackgroundTransparency = 1
|
||||
Wardrobe.Visible = false
|
||||
Wardrobe.Size = UDim2.new(1,0,1,0)
|
||||
Wardrobe.Parent = Backpack
|
||||
|
||||
local AssetList = Instance.new("Frame")
|
||||
AssetList.RobloxLocked = true
|
||||
AssetList.Name = "AssetList"
|
||||
AssetList.Position = UDim2.new(0,4,0,5)
|
||||
AssetList.Size = UDim2.new(0,85,1,-5)
|
||||
AssetList.BackgroundTransparency = 1
|
||||
AssetList.Visible = true
|
||||
AssetList.Parent = Wardrobe
|
||||
|
||||
local PreviewAssetFrame = Instance.new("Frame")
|
||||
PreviewAssetFrame.RobloxLocked = true
|
||||
PreviewAssetFrame.Name = "PreviewAssetFrame"
|
||||
PreviewAssetFrame.BackgroundTransparency = 1
|
||||
PreviewAssetFrame.Position = UDim2.new(1,-240,0,30)
|
||||
PreviewAssetFrame.Size = UDim2.new(0,250,0,250)
|
||||
PreviewAssetFrame.Parent = Wardrobe
|
||||
|
||||
local PreviewAssetBacking = Instance.new("TextButton")
|
||||
PreviewAssetBacking.RobloxLocked = true
|
||||
PreviewAssetBacking.Name = "PreviewAssetBacking"
|
||||
PreviewAssetBacking.Active = false
|
||||
PreviewAssetBacking.Text = ""
|
||||
PreviewAssetBacking.AutoButtonColor = false
|
||||
PreviewAssetBacking.Size = UDim2.new(1,0,1,0)
|
||||
PreviewAssetBacking.Style = Enum.ButtonStyle.RobloxButton
|
||||
PreviewAssetBacking.Visible = false
|
||||
PreviewAssetBacking.ZIndex = 9
|
||||
PreviewAssetBacking.Parent = PreviewAssetFrame
|
||||
|
||||
local PreviewAssetImage = Instance.new("ImageLabel")
|
||||
PreviewAssetImage.RobloxLocked = true
|
||||
PreviewAssetImage.Name = "PreviewAssetImage"
|
||||
PreviewAssetImage.BackgroundTransparency = 0.8
|
||||
PreviewAssetImage.Position = UDim2.new(0.5,-100,0,0)
|
||||
PreviewAssetImage.Size = UDim2.new(0,200,0,200)
|
||||
PreviewAssetImage.BorderSizePixel = 0
|
||||
PreviewAssetImage.ZIndex = 10
|
||||
PreviewAssetImage.Parent = PreviewAssetBacking
|
||||
|
||||
local AssetNameLabel = Instance.new("TextLabel")
|
||||
AssetNameLabel.Name = "AssetNameLabel"
|
||||
AssetNameLabel.RobloxLocked = true
|
||||
AssetNameLabel.BackgroundTransparency = 1
|
||||
AssetNameLabel.Position = UDim2.new(0,0,1,-20)
|
||||
AssetNameLabel.Size = UDim2.new(0.5,0,0,24)
|
||||
AssetNameLabel.ZIndex = 10
|
||||
AssetNameLabel.Font = Enum.Font.Arial
|
||||
AssetNameLabel.Text = ""
|
||||
AssetNameLabel.TextColor3 = Color3.new(1,1,1)
|
||||
AssetNameLabel.TextScaled = true
|
||||
AssetNameLabel.Parent = PreviewAssetBacking
|
||||
|
||||
local AssetTypeLabel = AssetNameLabel:clone()
|
||||
AssetTypeLabel.RobloxLocked = true
|
||||
AssetTypeLabel.Name = "AssetTypeLabel"
|
||||
AssetTypeLabel.TextScaled = false
|
||||
AssetTypeLabel.FontSize = Enum.FontSize.Size18
|
||||
AssetTypeLabel.Position = UDim2.new(0.5,3,1,-20)
|
||||
AssetTypeLabel.Parent = PreviewAssetBacking
|
||||
|
||||
|
||||
|
||||
local PreviewButton = Instance.new("TextButton")
|
||||
PreviewButton.RobloxLocked = true
|
||||
PreviewButton.Name = "PreviewButton"
|
||||
PreviewButton.Text = "Rotate"
|
||||
PreviewButton.BackgroundColor3 = Color3.new(0,0,0)
|
||||
PreviewButton.BackgroundTransparency = 0.5
|
||||
PreviewButton.BorderColor3 = Color3.new(1,1,1)
|
||||
PreviewButton.BorderSizePixel = 0
|
||||
PreviewButton.Position = UDim2.new(1.2,-62,1,-50)
|
||||
PreviewButton.Size = UDim2.new(0,125,0,50)
|
||||
PreviewButton.Font = Enum.Font.ArialBold
|
||||
PreviewButton.FontSize = Enum.FontSize.Size24
|
||||
PreviewButton.TextColor3 = Color3.new(1,1,1)
|
||||
PreviewButton.TextWrapped = true
|
||||
PreviewButton.TextStrokeTransparency = 0
|
||||
PreviewButton.Parent = Wardrobe
|
||||
|
||||
local CharacterPane = Instance.new("Frame")
|
||||
CharacterPane.RobloxLocked = true
|
||||
CharacterPane.Name = "CharacterPane"
|
||||
CharacterPane.Position = UDim2.new(1,-220,0,32)
|
||||
CharacterPane.Size = UDim2.new(0,220,1,-40)
|
||||
CharacterPane.BackgroundTransparency = 1
|
||||
CharacterPane.Visible = true
|
||||
CharacterPane.Parent = Wardrobe
|
||||
|
||||
--CharacterPane Children
|
||||
local FaceFrame = makeCharFrame("FacesFrame", CharacterPane)
|
||||
game:GetService("ContentProvider"):Preload("http://www.mete0r.xyz/asset/?id=75460621")
|
||||
makeZone("FaceZone","http://www.mete0r.xyz/asset/?id=75460621",UDim2.new(0,157,0,137),UDim2.new(0.5,-78,0.5,-68),FaceFrame)
|
||||
makeStyledButton("Face",UDim2.new(0,64,0,64),UDim2.new(0.5,-32,0.5,-135),FaceFrame)
|
||||
|
||||
local HeadFrame = makeCharFrame("HeadsFrame", CharacterPane)
|
||||
makeZone("FaceZone","http://www.mete0r.xyz/asset/?id=75460621",UDim2.new(0,157,0,137),UDim2.new(0.5,-78,0.5,-68),HeadFrame)
|
||||
makeStyledButton("Head",UDim2.new(0,64,0,64),UDim2.new(0.5,-32,0.5,-135),HeadFrame)
|
||||
|
||||
local HatsFrame = makeCharFrame("HatsFrame", CharacterPane)
|
||||
game:GetService("ContentProvider"):Preload("http://www.mete0r.xyz/asset/?id=75457888")
|
||||
local HatsZone = makeZone("HatsZone","http://www.mete0r.xyz/asset/?id=75457888",UDim2.new(0,186,0,184),UDim2.new(0.5,-93,0.5,-100), HatsFrame)
|
||||
makeStyledButton("Hat1Button",UDim2.new(0,64,0,64),UDim2.new(0,-1,0,-1),HatsZone,Enum.ButtonStyle.RobloxButton)
|
||||
makeStyledButton("Hat2Button",UDim2.new(0,64,0,64),UDim2.new(0,63,0,-1),HatsZone,Enum.ButtonStyle.RobloxButton)
|
||||
makeStyledButton("Hat3Button",UDim2.new(0,64,0,64),UDim2.new(0,127,0,-1),HatsZone,Enum.ButtonStyle.RobloxButton)
|
||||
|
||||
local PantsFrame = makeCharFrame("PantsFrame", CharacterPane)
|
||||
game:GetService("ContentProvider"):Preload("http://www.mete0r.xyz/asset/?id=75457920")
|
||||
makeZone("PantsZone","http://www.mete0r.xyz/asset/?id=75457920",UDim2.new(0,121,0,99),UDim2.new(0.5,-60,0.5,-100),PantsFrame)
|
||||
|
||||
local pantFrame = Instance.new("Frame")
|
||||
pantFrame.RobloxLocked = true
|
||||
pantFrame.Size = UDim2.new(0,25,0,56)
|
||||
pantFrame.Position = UDim2.new(0.5,-26,0.5,0)
|
||||
pantFrame.BackgroundColor3 = Color3.new(0,0,0)
|
||||
pantFrame.BorderColor3 = Color3.new(1,1,1)
|
||||
pantFrame.Name = "PantFrame"
|
||||
pantFrame.Parent = PantsFrame
|
||||
|
||||
local otherPantFrame = pantFrame:clone()
|
||||
otherPantFrame.Position = UDim2.new(0.5,3,0.5,0)
|
||||
otherPantFrame.RobloxLocked = true
|
||||
otherPantFrame.Parent = PantsFrame
|
||||
|
||||
local CurrentPants = Instance.new("ImageButton")
|
||||
CurrentPants.RobloxLocked = true
|
||||
CurrentPants.BackgroundTransparency = 1
|
||||
CurrentPants.ZIndex = 2
|
||||
CurrentPants.Name = "CurrentPants"
|
||||
CurrentPants.Position = UDim2.new(0.5,-31,0.5,-4)
|
||||
CurrentPants.Size = UDim2.new(0,54,0,59)
|
||||
CurrentPants.Parent = PantsFrame
|
||||
|
||||
local MeshFrame = makeCharFrame("PackagesFrame", CharacterPane)
|
||||
local torsoButton = makeStyledButton("TorsoMeshButton", UDim2.new(0,64,0,64),UDim2.new(0.5,-32,0.5,-110),MeshFrame,Enum.ButtonStyle.RobloxButton)
|
||||
makeTextLabel("TorsoLabel","Torso",UDim2.new(0.5,-16,0,-25),torsoButton)
|
||||
local leftLegButton = makeStyledButton("LeftLegMeshButton", UDim2.new(0,64,0,64),UDim2.new(0.5,0,0.5,-25),MeshFrame,Enum.ButtonStyle.RobloxButton)
|
||||
makeTextLabel("LeftLegLabel","Left Leg",UDim2.new(0.5,-16,0,-25),leftLegButton)
|
||||
local rightLegButton = makeStyledButton("RightLegMeshButton", UDim2.new(0,64,0,64),UDim2.new(0.5,-64,0.5,-25),MeshFrame,Enum.ButtonStyle.RobloxButton)
|
||||
makeTextLabel("RightLegLabel","Right Leg",UDim2.new(0.5,-16,0,-25),rightLegButton)
|
||||
local rightArmButton = makeStyledButton("RightArmMeshButton", UDim2.new(0,64,0,64),UDim2.new(0.5,-96,0.5,-110),MeshFrame,Enum.ButtonStyle.RobloxButton)
|
||||
makeTextLabel("RightArmLabel","Right Arm",UDim2.new(0.5,-16,0,-25),rightArmButton)
|
||||
local leftArmButton = makeStyledButton("LeftArmMeshButton", UDim2.new(0,64,0,64),UDim2.new(0.5,32,0.5,-110),MeshFrame,Enum.ButtonStyle.RobloxButton)
|
||||
makeTextLabel("LeftArmLabel","Left Arm",UDim2.new(0.5,-16,0,-25),leftArmButton)
|
||||
|
||||
local TShirtFrame = makeCharFrame("T-ShirtsFrame",CharacterPane)
|
||||
game:GetService("ContentProvider"):Preload("http://www.mete0r.xyz/asset/?id=75460642")
|
||||
makeZone("TShirtZone","http://www.mete0r.xyz/asset/?id=75460642",UDim2.new(0,121,0,154),UDim2.new(0.5,-60,0.5,-100),TShirtFrame)
|
||||
makeStyledButton("TShirtButton", UDim2.new(0,64,0,64),UDim2.new(0.5,-32,0.5,-64),TShirtFrame)
|
||||
|
||||
|
||||
local ShirtFrame = makeCharFrame("ShirtsFrame", CharacterPane)
|
||||
makeZone("ShirtZone","http://www.mete0r.xyz/asset/?id=75460642",UDim2.new(0,121,0,154),UDim2.new(0.5,-60,0.5,-100),ShirtFrame)
|
||||
makeStyledButton("ShirtButton", UDim2.new(0,64,0,64),UDim2.new(0.5,-32,0.5,-64),ShirtFrame)
|
||||
|
||||
|
||||
local ColorFrame = makeCharFrame("ColorFrame", CharacterPane)
|
||||
game:GetService("ContentProvider"):Preload("http://www.mete0r.xyz/asset/?id=76049888")
|
||||
local ColorZone = makeZone("ColorZone","http://www.mete0r.xyz/asset/?id=76049888", UDim2.new(0,120,0,150),UDim2.new(0.5,-60,0.5,-100),ColorFrame)
|
||||
makeStyledButton("Head",UDim2.new(0.26,0,0.19,0),UDim2.new(0.37,0,0.02,0),ColorZone).AutoButtonColor = false
|
||||
makeStyledButton("LeftArm",UDim2.new(0.19,0,0.36,0),UDim2.new(0.78,0,0.26,0),ColorZone).AutoButtonColor = false
|
||||
makeStyledButton("RightArm",UDim2.new(0.19,0,0.36,0),UDim2.new(0.025,0,0.26,0),ColorZone).AutoButtonColor = false
|
||||
makeStyledButton("Torso",UDim2.new(0.43,0,0.36,0),UDim2.new(0.28,0,0.26,0),ColorZone).AutoButtonColor = false
|
||||
makeStyledButton("RightLeg",UDim2.new(0.19,0,0.31,0),UDim2.new(0.275,0,0.67,0),ColorZone).AutoButtonColor = false
|
||||
makeStyledButton("LeftLeg",UDim2.new(0.19,0,0.31,0),UDim2.new(0.525,0,0.67,0),ColorZone).AutoButtonColor = false
|
||||
|
||||
-- Character Panel label (shows what category we are currently browsing)
|
||||
local CategoryLabel = Instance.new("TextLabel")
|
||||
CategoryLabel.RobloxLocked = true
|
||||
CategoryLabel.Name = "CategoryLabel"
|
||||
CategoryLabel.BackgroundTransparency = 1
|
||||
CategoryLabel.Font = Enum.Font.ArialBold
|
||||
CategoryLabel.FontSize = Enum.FontSize.Size18
|
||||
CategoryLabel.Position = UDim2.new(0,0,0,-7)
|
||||
CategoryLabel.Size = UDim2.new(1,0,0,20)
|
||||
CategoryLabel.TextXAlignment = Enum.TextXAlignment.Center
|
||||
CategoryLabel.Text = "All"
|
||||
CategoryLabel.TextColor3 = Color3.new(1,1,1)
|
||||
CategoryLabel.Parent = CharacterPane
|
||||
|
||||
--Save Button
|
||||
local SaveButton = Instance.new("TextButton")
|
||||
SaveButton.RobloxLocked = true
|
||||
SaveButton.Name = "SaveButton"
|
||||
SaveButton.Size = UDim2.new(0.6,0,0,50)
|
||||
SaveButton.Position = UDim2.new(0.2,0,1,-50)
|
||||
SaveButton.Style = Enum.ButtonStyle.RobloxButton
|
||||
SaveButton.Selected = false
|
||||
SaveButton.Font = Enum.Font.ArialBold
|
||||
SaveButton.FontSize = Enum.FontSize.Size18
|
||||
SaveButton.Text = "Save"
|
||||
SaveButton.TextColor3 = Color3.new(1,1,1)
|
||||
SaveButton.Parent = CharacterPane
|
||||
|
||||
-- no need for this to stick around
|
||||
|
||||
script:Destroy()
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
--rbxassetid%869%
|
||||
-- This script manages context switches in the backpack (Gear to Wardrobe, etc.) and player state changes. Also manages global functions across different tabs (currently only search)
|
||||
if game.CoreGui.Version < 7 then return end -- peace out if we aren't using the right client
|
||||
|
||||
-- basic functions
|
||||
local function waitForChild(instance, name)
|
||||
while not instance:FindFirstChild(name) do
|
||||
instance.ChildAdded:wait()
|
||||
end
|
||||
return instance:FindFirstChild(name)
|
||||
end
|
||||
local function waitForProperty(instance, property)
|
||||
while not instance[property] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
|
||||
-- don't do anything if we are in an empty game
|
||||
waitForChild(game,"Players")
|
||||
if #game.Players:GetChildren() < 1 then
|
||||
game.Players.ChildAdded:wait()
|
||||
end
|
||||
-- make sure everything is loaded in before we do anything
|
||||
-- get our local player
|
||||
waitForProperty(game.Players,"LocalPlayer")
|
||||
local player = game.Players.LocalPlayer
|
||||
|
||||
|
||||
|
||||
------------------------ Locals ------------------------------
|
||||
local backpack = script.Parent
|
||||
waitForChild(backpack,"Gear")
|
||||
|
||||
local screen = script.Parent.Parent
|
||||
assert(screen:IsA("ScreenGui"))
|
||||
|
||||
waitForChild(backpack, "Tabs")
|
||||
waitForChild(backpack.Tabs, "CloseButton")
|
||||
local closeButton = backpack.Tabs.CloseButton
|
||||
|
||||
waitForChild(backpack.Tabs, "InventoryButton")
|
||||
local inventoryButton = backpack.Tabs.InventoryButton
|
||||
if game.CoreGui.Version >= 8 then
|
||||
waitForChild(backpack.Tabs, "WardrobeButton")
|
||||
local wardrobeButton = backpack.Tabs.WardrobeButton
|
||||
end
|
||||
waitForChild(backpack.Parent,"ControlFrame")
|
||||
local backpackButton = waitForChild(backpack.Parent.ControlFrame,"BackpackButton")
|
||||
local currentTab = "gear"
|
||||
|
||||
local searchFrame = waitForChild(backpack,"SearchFrame")
|
||||
waitForChild(backpack.SearchFrame,"SearchBoxFrame")
|
||||
local searchBox = waitForChild(backpack.SearchFrame.SearchBoxFrame,"SearchBox")
|
||||
local searchButton = waitForChild(backpack.SearchFrame,"SearchButton")
|
||||
local resetButton = waitForChild(backpack.SearchFrame,"ResetButton")
|
||||
|
||||
local robloxGui = waitForChild(Game.CoreGui, 'RobloxGui')
|
||||
local currentLoadout = waitForChild(robloxGui, 'CurrentLoadout')
|
||||
|
||||
local canToggle = true
|
||||
local readyForNextEvent = true
|
||||
local backpackIsOpen = false
|
||||
local active = true
|
||||
local disabledByDeveloper = false
|
||||
|
||||
local humanoidDiedCon = nil
|
||||
|
||||
local backpackButtonPos
|
||||
|
||||
local guiTweenSpeed = 0.25 -- how quickly we open/close the backpack
|
||||
|
||||
local searchDefaultText = "Search..."
|
||||
local tilde = "~"
|
||||
local backquote = "`"
|
||||
|
||||
local backpackSize = UDim2.new(0, 600, 0, 400)
|
||||
|
||||
if robloxGui.AbsoluteSize.Y <= 500 then
|
||||
backpackSize = UDim2.new(0, 200, 0, 140)
|
||||
end
|
||||
|
||||
|
||||
------------------------ End Locals ---------------------------
|
||||
|
||||
|
||||
---------------------------------------- Public Event Setup ----------------------------------------
|
||||
|
||||
function createPublicEvent(eventName)
|
||||
assert(eventName, "eventName is nil")
|
||||
assert(tostring(eventName),"eventName is not a string")
|
||||
|
||||
local newEvent = Instance.new("BindableEvent")
|
||||
newEvent.Name = tostring(eventName)
|
||||
newEvent.Parent = script
|
||||
|
||||
return newEvent
|
||||
end
|
||||
|
||||
function createPublicFunction(funcName, invokeFunc)
|
||||
assert(funcName, "funcName is nil")
|
||||
assert(tostring(funcName), "funcName is not a string")
|
||||
assert(invokeFunc, "invokeFunc is nil")
|
||||
assert(type(invokeFunc) == "function", "invokeFunc should be of type 'function'")
|
||||
|
||||
local newFunction = Instance.new("BindableFunction")
|
||||
newFunction.Name = tostring(funcName)
|
||||
newFunction.OnInvoke = invokeFunc
|
||||
newFunction.Parent = script
|
||||
|
||||
return newFunction
|
||||
end
|
||||
|
||||
-- Events
|
||||
local resizeEvent = createPublicEvent("ResizeEvent")
|
||||
local backpackOpenEvent = createPublicEvent("BackpackOpenEvent")
|
||||
local backpackCloseEvent = createPublicEvent("BackpackCloseEvent")
|
||||
local tabClickedEvent = createPublicEvent("TabClickedEvent")
|
||||
local searchRequestedEvent = createPublicEvent("SearchRequestedEvent")
|
||||
---------------------------------------- End Public Event Setup ----------------------------------------
|
||||
|
||||
|
||||
|
||||
--------------------------- Internal Functions ----------------------------------------
|
||||
|
||||
function deactivateBackpack()
|
||||
backpack.Visible = false
|
||||
active = false
|
||||
end
|
||||
|
||||
function activateBackpack()
|
||||
initHumanoidDiedConnections()
|
||||
active = true
|
||||
backpack.Visible = backpackIsOpen
|
||||
if backpackIsOpen then
|
||||
toggleBackpack()
|
||||
end
|
||||
end
|
||||
|
||||
function initHumanoidDiedConnections()
|
||||
if humanoidDiedCon then
|
||||
humanoidDiedCon:disconnect()
|
||||
end
|
||||
waitForProperty(game.Players.LocalPlayer,"Character")
|
||||
waitForChild(game.Players.LocalPlayer.Character,"Humanoid")
|
||||
humanoidDiedCon = game.Players.LocalPlayer.Character.Humanoid.Died:connect(deactivateBackpack)
|
||||
end
|
||||
|
||||
local hideBackpack = function()
|
||||
backpackIsOpen = false
|
||||
readyForNextEvent = false
|
||||
backpackButton.Selected = false
|
||||
resetSearch()
|
||||
backpackCloseEvent:Fire(currentTab)
|
||||
backpack.Tabs.Visible = false
|
||||
searchFrame.Visible = false
|
||||
backpack:TweenSizeAndPosition(UDim2.new(0, backpackSize.X.Offset,0, 0), UDim2.new(0.5, -backpackSize.X.Offset/2, 1, -85), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, guiTweenSpeed, true,
|
||||
function()
|
||||
game.GuiService:RemoveCenterDialog(backpack)
|
||||
backpack.Visible = false
|
||||
backpackButton.Selected = false
|
||||
end)
|
||||
delay(guiTweenSpeed,function()
|
||||
game.GuiService:RemoveCenterDialog(backpack)
|
||||
backpack.Visible = false
|
||||
backpackButton.Selected = false
|
||||
readyForNextEvent = true
|
||||
canToggle = true
|
||||
end)
|
||||
end
|
||||
|
||||
function showBackpack()
|
||||
game.GuiService:AddCenterDialog(backpack, Enum.CenterDialogType.PlayerInitiatedDialog,
|
||||
function()
|
||||
backpack.Visible = true
|
||||
backpackButton.Selected = true
|
||||
end,
|
||||
function()
|
||||
backpack.Visible = false
|
||||
backpackButton.Selected = false
|
||||
end)
|
||||
backpack.Visible = true
|
||||
backpackButton.Selected = true
|
||||
backpack:TweenSizeAndPosition(backpackSize, UDim2.new(0.5, -backpackSize.X.Offset/2, 1, -backpackSize.Y.Offset - 88), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, guiTweenSpeed, true)
|
||||
delay(guiTweenSpeed,function()
|
||||
backpack.Tabs.Visible = false
|
||||
searchFrame.Visible = true
|
||||
backpackOpenEvent:Fire(currentTab)
|
||||
canToggle = true
|
||||
readyForNextEvent = true
|
||||
backpackButton.Image = "rbxasset://textures/ui/Backpack_Close.png"
|
||||
backpackButton.Position = UDim2.new(0.5, -7, 1, -backpackSize.Y.Offset - 108)
|
||||
end)
|
||||
end
|
||||
|
||||
function toggleBackpack()
|
||||
if not game.Players.LocalPlayer then return end
|
||||
if not game.Players.LocalPlayer["Character"] then return end
|
||||
if not canToggle then return end
|
||||
if not readyForNextEvent then return end
|
||||
readyForNextEvent = false
|
||||
canToggle = false
|
||||
|
||||
backpackIsOpen = not backpackIsOpen
|
||||
|
||||
if backpackIsOpen then
|
||||
showBackpack()
|
||||
else
|
||||
backpackButton.Position = UDim2.new(0.5, -7, 1, -55)
|
||||
backpackButton.Selected = false
|
||||
backpackButton.Image = "rbxasset://textures/ui/Backpack_Open.png"
|
||||
hideBackpack()
|
||||
|
||||
|
||||
local clChildren = currentLoadout:GetChildren()
|
||||
for i = 1, #clChildren do
|
||||
if clChildren[i] and clChildren[i]:IsA('Frame') then
|
||||
local frame = clChildren[i]
|
||||
if #frame:GetChildren() > 0 then
|
||||
backpackButton.Position = UDim2.new(0.5, -7, 1, -108)
|
||||
backpackButton.Visible = true
|
||||
if frame:GetChildren()[1]:IsA('ImageButton') then
|
||||
local imgButton = frame:GetChildren()[1]
|
||||
imgButton.Active = true
|
||||
imgButton.Draggable = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
function closeBackpack()
|
||||
if backpackIsOpen then
|
||||
toggleBackpack()
|
||||
end
|
||||
end
|
||||
|
||||
function setSelected(tab)
|
||||
assert(tab)
|
||||
assert(tab:IsA("TextButton"))
|
||||
|
||||
tab.BackgroundColor3 = Color3.new(1,1,1)
|
||||
tab.TextColor3 = Color3.new(0,0,0)
|
||||
tab.Selected = true
|
||||
tab.ZIndex = 3
|
||||
end
|
||||
|
||||
function setUnselected(tab)
|
||||
assert(tab)
|
||||
assert(tab:IsA("TextButton"))
|
||||
|
||||
tab.BackgroundColor3 = Color3.new(0,0,0)
|
||||
tab.TextColor3 = Color3.new(1,1,1)
|
||||
tab.Selected = false
|
||||
tab.ZIndex = 1
|
||||
end
|
||||
|
||||
function updateTabGui(selectedTab)
|
||||
assert(selectedTab)
|
||||
|
||||
if selectedTab == "gear" then
|
||||
setSelected(inventoryButton)
|
||||
setUnselected(wardrobeButton)
|
||||
elseif selectedTab == "wardrobe" then
|
||||
setSelected(wardrobeButton)
|
||||
setUnselected(inventoryButton)
|
||||
end
|
||||
end
|
||||
|
||||
function mouseLeaveTab(button)
|
||||
assert(button)
|
||||
assert(button:IsA("TextButton"))
|
||||
|
||||
if button.Selected then return end
|
||||
|
||||
button.BackgroundColor3 = Color3.new(0,0,0)
|
||||
end
|
||||
|
||||
function mouseOverTab(button)
|
||||
assert(button)
|
||||
assert(button:IsA("TextButton"))
|
||||
|
||||
if button.Selected then return end
|
||||
|
||||
button.BackgroundColor3 = Color3.new(39/255,39/255,39/255)
|
||||
end
|
||||
|
||||
function newTabClicked(tabName)
|
||||
assert(tabName)
|
||||
tabName = string.lower(tabName)
|
||||
currentTab = tabName
|
||||
|
||||
updateTabGui(tabName)
|
||||
tabClickedEvent:Fire(tabName)
|
||||
resetSearch()
|
||||
end
|
||||
|
||||
function trim(s)
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
function splitByWhitespace(text)
|
||||
if type(text) ~= "string" then return nil end
|
||||
|
||||
local terms = {}
|
||||
for token in string.gmatch(text, "[^%s]+") do
|
||||
if string.len(token) > 0 then
|
||||
table.insert(terms,token)
|
||||
end
|
||||
end
|
||||
return terms
|
||||
end
|
||||
|
||||
function resetSearchBoxGui()
|
||||
resetButton.Visible = false
|
||||
searchBox.Text = searchDefaultText
|
||||
end
|
||||
|
||||
function doSearch()
|
||||
local searchText = searchBox.Text
|
||||
if searchText == "" then
|
||||
resetSearch()
|
||||
return
|
||||
end
|
||||
searchText = trim(searchText)
|
||||
resetButton.Visible = true
|
||||
termTable = splitByWhitespace(searchText)
|
||||
searchRequestedEvent:Fire(searchText) -- todo: replace this with termtable when table passing is possible
|
||||
end
|
||||
|
||||
function resetSearch()
|
||||
resetSearchBoxGui()
|
||||
searchRequestedEvent:Fire()
|
||||
end
|
||||
|
||||
local backpackReady = function()
|
||||
readyForNextEvent = true
|
||||
end
|
||||
|
||||
function coreGuiChanged(coreGuiType,enabled)
|
||||
if coreGuiType == Enum.CoreGuiType.Backpack or coreGuiType == Enum.CoreGuiType.All then
|
||||
active = enabled
|
||||
disabledByDeveloper = not enabled
|
||||
|
||||
if disabledByDeveloper then
|
||||
game:GetService("GuiService"):RemoveKey(tilde)
|
||||
game:GetService("GuiService"):RemoveKey(backquote)
|
||||
else
|
||||
game:GetService("GuiService"):AddKey(tilde)
|
||||
game:GetService("GuiService"):AddKey(backquote)
|
||||
end
|
||||
|
||||
resetSearch()
|
||||
searchFrame.Visible = enabled and backpackIsOpen
|
||||
|
||||
currentLoadout.Visible = enabled
|
||||
backpack.Visible = false
|
||||
backpackButton.Visible = enabled
|
||||
end
|
||||
end
|
||||
|
||||
--------------------------- End Internal Functions -------------------------------------
|
||||
|
||||
|
||||
------------------------------ Public Functions Setup -------------------------------------
|
||||
createPublicFunction("CloseBackpack", hideBackpack)
|
||||
createPublicFunction("BackpackReady", backpackReady)
|
||||
------------------------------ End Public Functions Setup ---------------------------------
|
||||
|
||||
|
||||
------------------------ Connections/Script Main -------------------------------------------
|
||||
|
||||
coreGuiChanged(Enum.CoreGuiType.Backpack, Game.StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack))
|
||||
Game.StarterGui.CoreGuiChangedSignal:connect(coreGuiChanged)
|
||||
|
||||
inventoryButton.MouseButton1Click:connect(function() newTabClicked("gear") end)
|
||||
inventoryButton.MouseEnter:connect(function() mouseOverTab(inventoryButton) end)
|
||||
inventoryButton.MouseLeave:connect(function() mouseLeaveTab(inventoryButton) end)
|
||||
|
||||
if game.CoreGui.Version >= 8 then
|
||||
wardrobeButton.MouseButton1Click:connect(function() newTabClicked("wardrobe") end)
|
||||
wardrobeButton.MouseEnter:connect(function() mouseOverTab(wardrobeButton) end)
|
||||
wardrobeButton.MouseLeave:connect(function() mouseLeaveTab(wardrobeButton) end)
|
||||
end
|
||||
|
||||
closeButton.MouseButton1Click:connect(closeBackpack)
|
||||
|
||||
screen.Changed:connect(function(prop)
|
||||
if prop == "AbsoluteSize" then
|
||||
resizeEvent:Fire(screen.AbsoluteSize)
|
||||
end
|
||||
end)
|
||||
|
||||
-- GuiService key setup
|
||||
game:GetService("GuiService"):AddKey(tilde)
|
||||
game:GetService("GuiService"):AddKey(backquote)
|
||||
game:GetService("GuiService").KeyPressed:connect(function(key)
|
||||
if not active or disabledByDeveloper then return end
|
||||
if key == tilde or key == backquote then
|
||||
toggleBackpack()
|
||||
end
|
||||
end)
|
||||
backpackButton.MouseButton1Click:connect(function()
|
||||
if not active or disabledByDeveloper then return end
|
||||
toggleBackpack()
|
||||
end)
|
||||
|
||||
if game.Players.LocalPlayer["Character"] then
|
||||
activateBackpack()
|
||||
end
|
||||
|
||||
game.Players.LocalPlayer.CharacterAdded:connect(activateBackpack)
|
||||
|
||||
-- search functions
|
||||
searchBox.FocusLost:connect(function(enterPressed)
|
||||
if enterPressed or searchBox.Text ~= "" then
|
||||
doSearch()
|
||||
elseif searchBox.Text == "" then
|
||||
resetSearch()
|
||||
end
|
||||
end)
|
||||
searchButton.MouseButton1Click:connect(doSearch)
|
||||
resetButton.MouseButton1Click:connect(resetSearch)
|
||||
|
||||
if searchFrame and robloxGui.AbsoluteSize.Y <= 500 then
|
||||
searchFrame.RobloxLocked = false
|
||||
searchFrame:Destroy()
|
||||
end
|
||||
|
|
@ -0,0 +1,872 @@
|
|||
--rbxassetid%870%
|
||||
-- A couple of necessary functions
|
||||
local function waitForChild(instance, name)
|
||||
assert(instance)
|
||||
assert(name)
|
||||
while not instance:FindFirstChild(name) do
|
||||
instance.ChildAdded:wait()
|
||||
end
|
||||
return instance:FindFirstChild(name)
|
||||
end
|
||||
local function waitForProperty(instance, property)
|
||||
assert(instance)
|
||||
assert(property)
|
||||
while not instance[property] do
|
||||
instance.Changed:wait()
|
||||
end
|
||||
end
|
||||
|
||||
local function IsTouchDevice()
|
||||
return Game:GetService('UserInputService').TouchEnabled
|
||||
end
|
||||
|
||||
|
||||
waitForChild(game,"Players")
|
||||
waitForProperty(game.Players,"LocalPlayer")
|
||||
local player = game.Players.LocalPlayer
|
||||
|
||||
local RbxGui, msg = LoadLibrary("RbxGui")
|
||||
if not RbxGui then print("could not find RbxGui!") return end
|
||||
|
||||
--- Begin Locals
|
||||
local StaticTabName = "gear"
|
||||
|
||||
local backpack = script.Parent
|
||||
local screen = script.Parent.Parent
|
||||
|
||||
local backpackItems = {}
|
||||
local buttons = {}
|
||||
|
||||
local debounce = false
|
||||
local browsingMenu = false
|
||||
|
||||
local mouseEnterCons = {}
|
||||
local mouseClickCons = {}
|
||||
|
||||
local characterChildAddedCon = nil
|
||||
local characterChildRemovedCon = nil
|
||||
local backpackAddCon = nil
|
||||
|
||||
local playerBackpack = waitForChild(player,"Backpack")
|
||||
|
||||
waitForChild(backpack,"Tabs")
|
||||
|
||||
waitForChild(backpack,"Gear")
|
||||
local gearPreview = waitForChild(backpack.Gear,"GearPreview")
|
||||
|
||||
local scroller = waitForChild(backpack.Gear,"GearGridScrollingArea")
|
||||
|
||||
local currentLoadout = waitForChild(backpack.Parent,"CurrentLoadout")
|
||||
|
||||
local grid = waitForChild(backpack.Gear,"GearGrid")
|
||||
local gearButton = waitForChild(grid,"GearButton")
|
||||
|
||||
local swapSlot = waitForChild(script.Parent,"SwapSlot")
|
||||
|
||||
local backpackManager = waitForChild(script.Parent,"CoreScripts/BackpackScripts/BackpackManager")
|
||||
local backpackOpenEvent = waitForChild(backpackManager,"BackpackOpenEvent")
|
||||
local backpackCloseEvent = waitForChild(backpackManager,"BackpackCloseEvent")
|
||||
local tabClickedEvent = waitForChild(backpackManager,"TabClickedEvent")
|
||||
local resizeEvent = waitForChild(backpackManager,"ResizeEvent")
|
||||
local searchRequestedEvent = waitForChild(backpackManager,"SearchRequestedEvent")
|
||||
local tellBackpackReadyFunc = waitForChild(backpackManager,"BackpackReady")
|
||||
|
||||
-- creating scroll bar early as to make sure items get placed correctly
|
||||
local scrollFrame, scrollUp, scrollDown, recalculateScroll = RbxGui.CreateScrollingFrame(nil, "grid", Vector2.new(6, 6))
|
||||
|
||||
scrollFrame.Position = UDim2.new(0,0,0,30)
|
||||
scrollFrame.Size = UDim2.new(1,0,1,-30)
|
||||
scrollFrame.Parent = backpack.Gear.GearGrid
|
||||
|
||||
local scrollBar = Instance.new("Frame")
|
||||
scrollBar.Name = "ScrollBar"
|
||||
scrollBar.BackgroundTransparency = 0.9
|
||||
scrollBar.BackgroundColor3 = Color3.new(1,1,1)
|
||||
scrollBar.BorderSizePixel = 0
|
||||
scrollBar.Size = UDim2.new(0, 17, 1, -36)
|
||||
scrollBar.Position = UDim2.new(0,0,0,18)
|
||||
scrollBar.Parent = scroller
|
||||
|
||||
scrollDown.Position = UDim2.new(0,0,1,-17)
|
||||
|
||||
scrollUp.Parent = scroller
|
||||
scrollDown.Parent = scroller
|
||||
|
||||
local scrollFrameLoadout, scrollUpLoadout, scrollDownLoadout, recalculateScrollLoadout = RbxGui.CreateScrollingFrame()
|
||||
|
||||
scrollFrameLoadout.Position = UDim2.new(0,0,0,0)
|
||||
scrollFrameLoadout.Size = UDim2.new(1,0,1,0)
|
||||
scrollFrameLoadout.Parent = backpack.Gear.GearLoadouts.LoadoutsList
|
||||
|
||||
local LoadoutButton = Instance.new("TextButton")
|
||||
LoadoutButton.RobloxLocked = true
|
||||
LoadoutButton.Name = "LoadoutButton"
|
||||
LoadoutButton.Font = Enum.Font.ArialBold
|
||||
LoadoutButton.FontSize = Enum.FontSize.Size14
|
||||
LoadoutButton.Position = UDim2.new(0,0,0,0)
|
||||
LoadoutButton.Size = UDim2.new(1,0,0,32)
|
||||
LoadoutButton.Style = Enum.ButtonStyle.RobloxButton
|
||||
LoadoutButton.Text = "Loadout #1"
|
||||
LoadoutButton.TextColor3 = Color3.new(1,1,1)
|
||||
LoadoutButton.Parent = scrollFrameLoadout
|
||||
|
||||
local LoadoutButtonTwo = LoadoutButton:clone()
|
||||
LoadoutButtonTwo.Text = "Loadout #2"
|
||||
LoadoutButtonTwo.Parent = scrollFrameLoadout
|
||||
|
||||
local LoadoutButtonThree = LoadoutButton:clone()
|
||||
LoadoutButtonThree.Text = "Loadout #3"
|
||||
LoadoutButtonThree.Parent = scrollFrameLoadout
|
||||
|
||||
local LoadoutButtonFour = LoadoutButton:clone()
|
||||
LoadoutButtonFour.Text = "Loadout #4"
|
||||
LoadoutButtonFour.Parent = scrollFrameLoadout
|
||||
|
||||
local scrollBarLoadout = Instance.new("Frame")
|
||||
scrollBarLoadout.Name = "ScrollBarLoadout"
|
||||
scrollBarLoadout.BackgroundTransparency = 0.9
|
||||
scrollBarLoadout.BackgroundColor3 = Color3.new(1,1,1)
|
||||
scrollBarLoadout.BorderSizePixel = 0
|
||||
scrollBarLoadout.Size = UDim2.new(0, 17, 1, -36)
|
||||
scrollBarLoadout.Position = UDim2.new(0,0,0,18)
|
||||
scrollBarLoadout.Parent = backpack.Gear.GearLoadouts.GearLoadoutsScrollingArea
|
||||
|
||||
scrollDownLoadout.Position = UDim2.new(0,0,1,-17)
|
||||
|
||||
scrollUpLoadout.Parent = backpack.Gear.GearLoadouts.GearLoadoutsScrollingArea
|
||||
scrollDownLoadout.Parent = backpack.Gear.GearLoadouts.GearLoadoutsScrollingArea
|
||||
|
||||
|
||||
-- Begin Functions
|
||||
function removeFromMap(map,object)
|
||||
for i = 1, #map do
|
||||
if map[i] == object then
|
||||
table.remove(map,i)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function robloxLock(instance)
|
||||
instance.RobloxLocked = true
|
||||
children = instance:GetChildren()
|
||||
if children then
|
||||
for i, child in ipairs(children) do
|
||||
robloxLock(child)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function resize()
|
||||
local size = 0
|
||||
if gearPreview.AbsoluteSize.Y > gearPreview.AbsoluteSize.X then
|
||||
size = gearPreview.AbsoluteSize.X * 0.75
|
||||
else
|
||||
size = gearPreview.AbsoluteSize.Y * 0.75
|
||||
end
|
||||
|
||||
waitForChild(gearPreview,"GearImage")
|
||||
gearPreview.GearImage.Size = UDim2.new(0,size,0,size)
|
||||
gearPreview.GearImage.Position = UDim2.new(0,gearPreview.AbsoluteSize.X/2 - size/2,0.75,-size)
|
||||
|
||||
resizeGrid()
|
||||
end
|
||||
|
||||
function addToGrid(child)
|
||||
if not child:IsA("Tool") then
|
||||
if not child:IsA("HopperBin") then
|
||||
return
|
||||
end
|
||||
end
|
||||
if child:FindFirstChild("RobloxBuildTool") then return end
|
||||
|
||||
for i,v in pairs(backpackItems) do -- check to see if we already have this gear registered
|
||||
if v == child then return end
|
||||
end
|
||||
|
||||
table.insert(backpackItems,child)
|
||||
|
||||
local changeCon = child.Changed:connect(function(prop)
|
||||
if prop == "Name" then
|
||||
if buttons[child] then
|
||||
if buttons[child].Image == "" then
|
||||
buttons[child].GearText.Text = child.Name
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
local ancestryCon = nil
|
||||
ancestryCon = child.AncestryChanged:connect(function(theChild,theParent)
|
||||
local thisObject = nil
|
||||
for k,v in pairs(backpackItems) do
|
||||
if v == child then
|
||||
thisObject = v
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
waitForProperty(player,"Character")
|
||||
waitForChild(player,"Backpack")
|
||||
if (child.Parent ~= player.Backpack and child.Parent ~= player.Character) then
|
||||
if ancestryCon then ancestryCon:disconnect() end
|
||||
if changeCon then changeCon:disconnect() end
|
||||
|
||||
for k,v in pairs(backpackItems) do
|
||||
if v == thisObject then
|
||||
if mouseEnterCons[buttons[v]] then mouseEnterCons[buttons[v]]:disconnect() end
|
||||
if mouseClickCons[buttons[v]] then mouseClickCons[buttons[v]]:disconnect() end
|
||||
buttons[v].Parent = nil
|
||||
buttons[v] = nil
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
removeFromMap(backpackItems,thisObject)
|
||||
|
||||
resizeGrid()
|
||||
else
|
||||
resizeGrid()
|
||||
end
|
||||
updateGridActive()
|
||||
end)
|
||||
resizeGrid()
|
||||
end
|
||||
|
||||
function buttonClick(button)
|
||||
if button:FindFirstChild("UnequipContextMenu") and not button.Active then
|
||||
button.UnequipContextMenu.Visible = true
|
||||
browsingMenu = true
|
||||
end
|
||||
end
|
||||
|
||||
function previewGear(button)
|
||||
if not browsingMenu then
|
||||
gearPreview.Visible = false
|
||||
gearPreview.GearImage.Image = button.Image
|
||||
gearPreview.GearStats.GearName.Text = button.GearReference.Value.Name
|
||||
end
|
||||
end
|
||||
|
||||
function findEmptySlot()
|
||||
local smallestNum = nil
|
||||
local loadout = currentLoadout:GetChildren()
|
||||
for i = 1, #loadout do
|
||||
if loadout[i]:IsA("Frame") and #loadout[i]:GetChildren() <= 0 then
|
||||
local frameNum = tonumber(string.sub(loadout[i].Name,5))
|
||||
if frameNum == 0 then frameNum = 10 end
|
||||
if not smallestNum or (smallestNum > frameNum) then
|
||||
smallestNum = frameNum
|
||||
end
|
||||
end
|
||||
end
|
||||
if smallestNum == 10 then smallestNum = 0 end
|
||||
return smallestNum
|
||||
end
|
||||
|
||||
function checkForSwap(button,x,y)
|
||||
local loadoutChildren = currentLoadout:GetChildren()
|
||||
for i = 1, #loadoutChildren do
|
||||
if loadoutChildren[i]:IsA("Frame") and string.find(loadoutChildren[i].Name,"Slot") then
|
||||
if x >= loadoutChildren[i].AbsolutePosition.x and x <= (loadoutChildren[i].AbsolutePosition.x + loadoutChildren[i].AbsoluteSize.x) then
|
||||
if y >= loadoutChildren[i].AbsolutePosition.y and y <= (loadoutChildren[i].AbsolutePosition.y + loadoutChildren[i].AbsoluteSize.y) then
|
||||
local slot = tonumber(string.sub(loadoutChildren[i].Name,5))
|
||||
swapGearSlot(slot,button)
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function resizeGrid()
|
||||
for k,v in pairs(backpackItems) do
|
||||
if not v:FindFirstChild("RobloxBuildTool") then
|
||||
if not buttons[v] then
|
||||
local buttonClone = gearButton:clone()
|
||||
buttonClone.Parent = grid.ScrollingFrame
|
||||
buttonClone.Visible = true
|
||||
buttonClone.Image = v.TextureId
|
||||
if buttonClone.Image == "" then
|
||||
buttonClone.GearText.Text = v.Name
|
||||
end
|
||||
|
||||
buttonClone.GearReference.Value = v
|
||||
buttonClone.Draggable = true
|
||||
buttons[v] = buttonClone
|
||||
|
||||
|
||||
if not IsTouchDevice() then
|
||||
local unequipMenu = getGearContextMenu()
|
||||
|
||||
|
||||
unequipMenu.Visible = false
|
||||
unequipMenu.Parent = buttonClone
|
||||
end
|
||||
|
||||
local beginPos = nil
|
||||
buttonClone.DragBegin:connect(function(value)
|
||||
waitForChild(buttonClone, 'Background')
|
||||
buttonClone['Background'].ZIndex = 10
|
||||
buttonClone.ZIndex = 10
|
||||
beginPos = value
|
||||
end)
|
||||
buttonClone.DragStopped:connect(function(x,y)
|
||||
waitForChild(buttonClone, 'Background')
|
||||
buttonClone['Background'].ZIndex = 1.0
|
||||
buttonClone.ZIndex = 2
|
||||
if beginPos ~= buttonClone.Position then
|
||||
if not checkForSwap(buttonClone,x,y) then
|
||||
buttonClone:TweenPosition(beginPos,Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.5, true)
|
||||
buttonClone.Draggable = false
|
||||
delay(0.5,function()
|
||||
buttonClone.Draggable = true
|
||||
end)
|
||||
else
|
||||
buttonClone.Position = beginPos
|
||||
end
|
||||
end
|
||||
end)
|
||||
local clickTime = tick()
|
||||
mouseEnterCons[buttonClone] = buttonClone.MouseEnter:connect(function() previewGear(buttonClone) end)
|
||||
mouseClickCons[buttonClone] = buttonClone.MouseButton1Click:connect(function()
|
||||
local newClickTime = tick()
|
||||
if buttonClone.Active and (newClickTime - clickTime) < 0.5 then
|
||||
local slot = findEmptySlot()
|
||||
if slot then
|
||||
buttonClone.ZIndex = 1
|
||||
swapGearSlot(slot,buttonClone)
|
||||
end
|
||||
else
|
||||
buttonClick(buttonClone)
|
||||
end
|
||||
clickTime = newClickTime
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
recalculateScroll()
|
||||
end
|
||||
|
||||
function showPartialGrid(subset)
|
||||
for k,v in pairs(buttons) do
|
||||
v.Parent = nil
|
||||
end
|
||||
if subset then
|
||||
for k,v in pairs(subset) do
|
||||
v.Parent = grid.ScrollingFrame
|
||||
end
|
||||
end
|
||||
recalculateScroll()
|
||||
end
|
||||
|
||||
function showEntireGrid()
|
||||
for k,v in pairs(buttons) do
|
||||
v.Parent = grid.ScrollingFrame
|
||||
end
|
||||
recalculateScroll()
|
||||
end
|
||||
|
||||
function inLoadout(gear)
|
||||
local children = currentLoadout:GetChildren()
|
||||
for i = 1, #children do
|
||||
if children[i]:IsA("Frame") then
|
||||
local button = children[i]:GetChildren()
|
||||
if #button > 0 then
|
||||
if button[1].GearReference.Value and button[1].GearReference.Value == gear then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function updateGridActive()
|
||||
for k,v in pairs(backpackItems) do
|
||||
if buttons[v] then
|
||||
local gear = nil
|
||||
local gearRef = buttons[v]:FindFirstChild("GearReference")
|
||||
|
||||
if gearRef then gear = gearRef.Value end
|
||||
|
||||
if not gear then
|
||||
buttons[v].Active = false
|
||||
elseif inLoadout(gear) then
|
||||
buttons[v].Active = false
|
||||
else
|
||||
buttons[v].Active = true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function centerGear(loadoutChildren)
|
||||
local gearButtons = {}
|
||||
local lastSlotAdd = nil
|
||||
for i = 1, #loadoutChildren do
|
||||
if loadoutChildren[i]:IsA("Frame") and #loadoutChildren[i]:GetChildren() > 0 then
|
||||
if loadoutChildren[i].Name == "Slot0" then
|
||||
lastSlotAdd = loadoutChildren[i]
|
||||
else
|
||||
table.insert(gearButtons, loadoutChildren[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
if lastSlotAdd then table.insert(gearButtons,lastSlotAdd) end
|
||||
|
||||
local startPos = ( 1 - (#gearButtons * 0.1) ) / 2
|
||||
for i = 1, #gearButtons do
|
||||
gearButtons[i]:TweenPosition(UDim2.new(startPos + ((i - 1) * 0.1),0,0,0), Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.25, true)
|
||||
end
|
||||
end
|
||||
|
||||
function tabClickHandler(tabName)
|
||||
if tabName == StaticTabName then
|
||||
backpackOpenHandler(tabName)
|
||||
else
|
||||
backpackCloseHandler(tabName)
|
||||
end
|
||||
end
|
||||
|
||||
function backpackOpenHandler(currentTab)
|
||||
if currentTab and currentTab ~= StaticTabName then
|
||||
backpack.Gear.Visible = false
|
||||
return
|
||||
end
|
||||
|
||||
backpack.Gear.Visible = true
|
||||
updateGridActive()
|
||||
|
||||
resizeGrid()
|
||||
resize()
|
||||
tellBackpackReadyFunc:Invoke()
|
||||
end
|
||||
|
||||
function backpackCloseHandler(currentTab)
|
||||
if currentTab and currentTab ~= StaticTabName then
|
||||
backpack.Gear.Visible = false
|
||||
return
|
||||
end
|
||||
|
||||
backpack.Gear.Visible = false
|
||||
|
||||
resizeGrid()
|
||||
resize()
|
||||
tellBackpackReadyFunc:Invoke()
|
||||
end
|
||||
|
||||
function loadoutCheck(child, selectState)
|
||||
if not child:IsA("ImageButton") then return end
|
||||
for k,v in pairs(backpackItems) do
|
||||
if buttons[v] then
|
||||
if child:FindFirstChild("GearReference") and buttons[v]:FindFirstChild("GearReference") then
|
||||
if buttons[v].GearReference.Value == child.GearReference.Value then
|
||||
buttons[v].Active = selectState
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function clearPreview()
|
||||
gearPreview.GearImage.Image = ""
|
||||
gearPreview.GearStats.GearName.Text = ""
|
||||
end
|
||||
|
||||
function removeAllEquippedGear(physGear)
|
||||
local stuff = player.Character:GetChildren()
|
||||
for i = 1, #stuff do
|
||||
if ( stuff[i]:IsA("Tool") or stuff[i]:IsA("HopperBin") ) and stuff[i] ~= physGear then
|
||||
stuff[i].Parent = playerBackpack
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function equipGear(physGear)
|
||||
removeAllEquippedGear(physGear)
|
||||
physGear.Parent = player.Character
|
||||
updateGridActive()
|
||||
end
|
||||
|
||||
function unequipGear(physGear)
|
||||
physGear.Parent = playerBackpack
|
||||
updateGridActive()
|
||||
end
|
||||
|
||||
function highlight(button)
|
||||
button.TextColor3 = Color3.new(0,0,0)
|
||||
button.BackgroundColor3 = Color3.new(0.8,0.8,0.8)
|
||||
end
|
||||
function clearHighlight(button)
|
||||
button.TextColor3 = Color3.new(1,1,1)
|
||||
button.BackgroundColor3 = Color3.new(0,0,0)
|
||||
end
|
||||
|
||||
function swapGearSlot(slot,gearButton)
|
||||
if not swapSlot.Value then -- signal loadout to swap a gear out
|
||||
swapSlot.Slot.Value = slot
|
||||
swapSlot.GearButton.Value = gearButton
|
||||
swapSlot.Value = true
|
||||
updateGridActive()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local UnequipGearMenuClick = function(element, menu)
|
||||
if type(element.Action) ~= "number" then return end
|
||||
local num = element.Action
|
||||
if num == 1 then -- remove from loadout
|
||||
unequipGear(menu.Parent.GearReference.Value)
|
||||
local inventoryButton = menu.Parent
|
||||
local gearToUnequip = inventoryButton.GearReference.Value
|
||||
local loadoutChildren = currentLoadout:GetChildren()
|
||||
local slot = -1
|
||||
for i = 1, #loadoutChildren do
|
||||
if loadoutChildren[i]:IsA("Frame") then
|
||||
local button = loadoutChildren[i]:GetChildren()
|
||||
if button[1] and button[1].GearReference.Value == gearToUnequip then
|
||||
slot = button[1].SlotNumber.Text
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
swapGearSlot(slot,nil)
|
||||
end
|
||||
end
|
||||
|
||||
function setupCharacterConnections()
|
||||
|
||||
if backpackAddCon then backpackAddCon:disconnect() end
|
||||
backpackAddCon = game.Players.LocalPlayer.Backpack.ChildAdded:connect(function(child) addToGrid(child) end)
|
||||
|
||||
-- make sure we get all the children
|
||||
local backpackChildren = game.Players.LocalPlayer.Backpack:GetChildren()
|
||||
for i = 1, #backpackChildren do
|
||||
addToGrid(backpackChildren[i])
|
||||
end
|
||||
|
||||
if characterChildAddedCon then characterChildAddedCon:disconnect() end
|
||||
characterChildAddedCon =
|
||||
game.Players.LocalPlayer.Character.ChildAdded:connect(function(child)
|
||||
addToGrid(child)
|
||||
updateGridActive()
|
||||
end)
|
||||
|
||||
if characterChildRemovedCon then characterChildRemovedCon:disconnect() end
|
||||
characterChildRemovedCon =
|
||||
game.Players.LocalPlayer.Character.ChildRemoved:connect(function(child)
|
||||
updateGridActive()
|
||||
end)
|
||||
|
||||
wait()
|
||||
centerGear(currentLoadout:GetChildren())
|
||||
end
|
||||
|
||||
function removeCharacterConnections()
|
||||
if characterChildAddedCon then characterChildAddedCon:disconnect() end
|
||||
if characterChildRemovedCon then characterChildRemovedCon:disconnect() end
|
||||
if backpackAddCon then backpackAddCon:disconnect() end
|
||||
end
|
||||
|
||||
function trim(s)
|
||||
return (s:gsub("^%s*(.-)%s*$", "%1"))
|
||||
end
|
||||
|
||||
function filterGear(terms)
|
||||
local filteredGear = {}
|
||||
for k,v in pairs(backpackItems) do
|
||||
if buttons[v] then
|
||||
local gearString = string.lower(buttons[v].GearReference.Value.Name)
|
||||
gearString = trim(gearString)
|
||||
for i = 1, #terms do
|
||||
if string.match(gearString,terms[i]) then
|
||||
table.insert(filteredGear,buttons[v])
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return filteredGear
|
||||
end
|
||||
function splitByWhitespace(text)
|
||||
if type(text) ~= "string" then return nil end
|
||||
|
||||
local terms = {}
|
||||
for token in string.gmatch(text, "[^%s]+") do
|
||||
if string.len(token) > 0 then
|
||||
table.insert(terms,token)
|
||||
end
|
||||
end
|
||||
return terms
|
||||
end
|
||||
function showSearchGear(searchTerms)
|
||||
if not backpack.Gear.Visible then return end -- currently not active tab
|
||||
|
||||
local searchTermTable = splitByWhitespace(searchTerms)
|
||||
if searchTermTable and (#searchTermTable > 0) then
|
||||
currSearchTerms = searchTermTable
|
||||
else
|
||||
currSearchTerms = nil
|
||||
end
|
||||
|
||||
if searchTermTable == nil then
|
||||
showEntireGrid()
|
||||
return
|
||||
end
|
||||
|
||||
local filteredButtons = filterGear(currSearchTerms)
|
||||
showPartialGrid(filteredButtons)
|
||||
end
|
||||
|
||||
function nukeBackpack()
|
||||
while #buttons > 0 do
|
||||
table.remove(buttons)
|
||||
end
|
||||
buttons = {}
|
||||
while #backpackItems > 0 do
|
||||
table.remove(backpackItems)
|
||||
end
|
||||
backpackItems = {}
|
||||
local scrollingFrameChildren = grid.ScrollingFrame:GetChildren()
|
||||
for i = 1, #scrollingFrameChildren do
|
||||
scrollingFrameChildren[i]:remove()
|
||||
end
|
||||
end
|
||||
|
||||
function getGearContextMenu()
|
||||
local gearContextMenu = Instance.new("Frame")
|
||||
gearContextMenu.Active = true
|
||||
gearContextMenu.Name = "UnequipContextMenu"
|
||||
gearContextMenu.Size = UDim2.new(0,115,0,70)
|
||||
gearContextMenu.Position = UDim2.new(0,-16,0,-16)
|
||||
gearContextMenu.BackgroundTransparency = 1
|
||||
gearContextMenu.Visible = false
|
||||
|
||||
local gearContextMenuButton = Instance.new("TextButton")
|
||||
gearContextMenuButton.Name = "UnequipContextMenuButton"
|
||||
gearContextMenuButton.Text = ""
|
||||
gearContextMenuButton.Style = Enum.ButtonStyle.RobloxButtonDefault
|
||||
gearContextMenuButton.ZIndex = 8
|
||||
gearContextMenuButton.Size = UDim2.new(1, 0, 1, -20)
|
||||
gearContextMenuButton.Visible = true
|
||||
gearContextMenuButton.Parent = gearContextMenu
|
||||
|
||||
local elementHeight = 12
|
||||
|
||||
local contextMenuElements = {}
|
||||
local contextMenuElementsName = {"Remove Hotkey"}
|
||||
|
||||
for i = 1, #contextMenuElementsName do
|
||||
local element = {}
|
||||
element.Type = "Button"
|
||||
element.Text = contextMenuElementsName[i]
|
||||
element.Action = i
|
||||
element.DoIt = UnequipGearMenuClick
|
||||
table.insert(contextMenuElements,element)
|
||||
end
|
||||
|
||||
for i, contextElement in ipairs(contextMenuElements) do
|
||||
local element = contextElement
|
||||
if element.Type == "Button" then
|
||||
local button = Instance.new("TextButton")
|
||||
button.Name = "UnequipContextButton" .. i
|
||||
button.BackgroundColor3 = Color3.new(0,0,0)
|
||||
button.BorderSizePixel = 0
|
||||
button.TextXAlignment = Enum.TextXAlignment.Left
|
||||
button.Text = " " .. contextElement.Text
|
||||
button.Font = Enum.Font.Arial
|
||||
button.FontSize = Enum.FontSize.Size14
|
||||
button.Size = UDim2.new(1, 8, 0, elementHeight)
|
||||
button.Position = UDim2.new(0,0,0,elementHeight * i)
|
||||
button.TextColor3 = Color3.new(1,1,1)
|
||||
button.ZIndex = 9
|
||||
button.Parent = gearContextMenuButton
|
||||
|
||||
if not IsTouchDevice() then
|
||||
|
||||
button.MouseButton1Click:connect(function()
|
||||
if button.Active and not gearContextMenu.Parent.Active then
|
||||
local success, result = pcall(function() element.DoIt(element, gearContextMenu) end)
|
||||
browsingMenu = false
|
||||
gearContextMenu.Visible = false
|
||||
clearHighlight(button)
|
||||
clearPreview()
|
||||
end
|
||||
end)
|
||||
|
||||
button.MouseEnter:connect(function()
|
||||
if button.Active and gearContextMenu.Parent.Active then
|
||||
highlight(button)
|
||||
end
|
||||
end)
|
||||
button.MouseLeave:connect(function()
|
||||
if button.Active and gearContextMenu.Parent.Active then
|
||||
clearHighlight(button)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
contextElement.Button = button
|
||||
contextElement.Element = button
|
||||
elseif element.Type == "Label" then
|
||||
local frame = Instance.new("Frame")
|
||||
frame.Name = "ContextLabel" .. i
|
||||
frame.BackgroundTransparency = 1
|
||||
frame.Size = UDim2.new(1, 8, 0, elementHeight)
|
||||
|
||||
local label = Instance.new("TextLabel")
|
||||
label.Name = "Text1"
|
||||
label.BackgroundTransparency = 1
|
||||
label.BackgroundColor3 = Color3.new(1,1,1)
|
||||
label.BorderSizePixel = 0
|
||||
label.TextXAlignment = Enum.TextXAlignment.Left
|
||||
label.Font = Enum.Font.ArialBold
|
||||
label.FontSize = Enum.FontSize.Size14
|
||||
label.Position = UDim2.new(0.0, 0, 0, 0)
|
||||
label.Size = UDim2.new(0.5, 0, 1, 0)
|
||||
label.TextColor3 = Color3.new(1,1,1)
|
||||
label.ZIndex = 9
|
||||
label.Parent = frame
|
||||
element.Label1 = label
|
||||
|
||||
if element.GetText2 then
|
||||
label = Instance.new("TextLabel")
|
||||
label.Name = "Text2"
|
||||
label.BackgroundTransparency = 1
|
||||
label.BackgroundColor3 = Color3.new(1,1,1)
|
||||
label.BorderSizePixel = 0
|
||||
label.TextXAlignment = Enum.TextXAlignment.Right
|
||||
label.Font = Enum.Font.Arial
|
||||
label.FontSize = Enum.FontSize.Size14
|
||||
label.Position = UDim2.new(0.5, 0, 0, 0)
|
||||
label.Size = UDim2.new(0.5, 0, 1, 0)
|
||||
label.TextColor3 = Color3.new(1,1,1)
|
||||
label.ZIndex = 9
|
||||
label.Parent = frame
|
||||
element.Label2 = label
|
||||
end
|
||||
frame.Parent = gearContextMenuButton
|
||||
element.Label = frame
|
||||
element.Element = frame
|
||||
end
|
||||
end
|
||||
|
||||
gearContextMenu.ZIndex = 4
|
||||
gearContextMenu.MouseLeave:connect(function()
|
||||
browsingMenu = false
|
||||
gearContextMenu.Visible = false
|
||||
clearPreview()
|
||||
end)
|
||||
robloxLock(gearContextMenu)
|
||||
|
||||
return gearContextMenu
|
||||
end
|
||||
|
||||
function coreGuiChanged(coreGuiType,enabled)
|
||||
if coreGuiType == Enum.CoreGuiType.Backpack or coreGuiType == Enum.CoreGuiType.All then
|
||||
if not enabled then
|
||||
backpack.Gear.Visible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local backpackChildren = player.Backpack:GetChildren()
|
||||
for i = 1, #backpackChildren do
|
||||
addToGrid(backpackChildren[i])
|
||||
end
|
||||
|
||||
------------------------- Start Lifelong Connections -----------------------
|
||||
|
||||
|
||||
resizeEvent.Event:connect(function(absSize)
|
||||
if debounce then return end
|
||||
|
||||
debounce = true
|
||||
wait()
|
||||
resize()
|
||||
resizeGrid()
|
||||
debounce = false
|
||||
end)
|
||||
|
||||
currentLoadout.ChildAdded:connect(function(child) loadoutCheck(child, false) end)
|
||||
currentLoadout.ChildRemoved:connect(function(child) loadoutCheck(child, true) end)
|
||||
|
||||
currentLoadout.DescendantAdded:connect(function(descendant)
|
||||
if not backpack.Visible and ( descendant:IsA("ImageButton") or descendant:IsA("TextButton") ) then
|
||||
centerGear(currentLoadout:GetChildren())
|
||||
end
|
||||
end)
|
||||
currentLoadout.DescendantRemoving:connect(function(descendant)
|
||||
if not backpack.Visible and ( descendant:IsA("ImageButton") or descendant:IsA("TextButton") ) then
|
||||
wait()
|
||||
centerGear(currentLoadout:GetChildren())
|
||||
end
|
||||
end)
|
||||
|
||||
grid.MouseEnter:connect(function() clearPreview() end)
|
||||
grid.MouseLeave:connect(function() clearPreview() end)
|
||||
|
||||
player.CharacterRemoving:connect(function()
|
||||
removeCharacterConnections()
|
||||
nukeBackpack()
|
||||
end)
|
||||
player.CharacterAdded:connect(function() setupCharacterConnections() end)
|
||||
|
||||
player.ChildAdded:connect(function(child)
|
||||
if child:IsA("Backpack") then
|
||||
playerBackpack = child
|
||||
if backpackAddCon then backpackAddCon:disconnect() end
|
||||
backpackAddCon = game.Players.LocalPlayer.Backpack.ChildAdded:connect(function(child) addToGrid(child) end)
|
||||
end
|
||||
end)
|
||||
|
||||
swapSlot.Changed:connect(function()
|
||||
if not swapSlot.Value then
|
||||
updateGridActive()
|
||||
end
|
||||
end)
|
||||
|
||||
local loadoutChildren = currentLoadout:GetChildren()
|
||||
for i = 1, #loadoutChildren do
|
||||
if loadoutChildren[i]:IsA("Frame") and string.find(loadoutChildren[i].Name,"Slot") then
|
||||
loadoutChildren[i].ChildRemoved:connect(function()
|
||||
updateGridActive()
|
||||
end)
|
||||
loadoutChildren[i].ChildAdded:connect(function()
|
||||
updateGridActive()
|
||||
end)
|
||||
end
|
||||
end
|
||||
------------------------- End Lifelong Connections -----------------------
|
||||
|
||||
coreGuiChanged(Enum.CoreGuiType.Backpack, Game.StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack))
|
||||
Game.StarterGui.CoreGuiChangedSignal:connect(coreGuiChanged)
|
||||
|
||||
resize()
|
||||
resizeGrid()
|
||||
|
||||
-- make sure any items in the loadout are accounted for in inventory
|
||||
local loadoutChildren = currentLoadout:GetChildren()
|
||||
for i = 1, #loadoutChildren do
|
||||
loadoutCheck(loadoutChildren[i], false)
|
||||
end
|
||||
if not backpack.Visible then centerGear(currentLoadout:GetChildren()) end
|
||||
|
||||
-- make sure that inventory is listening to gear reparenting
|
||||
if characterChildAddedCon == nil and game.Players.LocalPlayer["Character"] then
|
||||
setupCharacterConnections()
|
||||
end
|
||||
if not backpackAddCon then
|
||||
backpackAddCon = game.Players.LocalPlayer.Backpack.ChildAdded:connect(function(child) addToGrid(child) end)
|
||||
end
|
||||
|
||||
backpackOpenEvent.Event:connect(backpackOpenHandler)
|
||||
backpackCloseEvent.Event:connect(backpackCloseHandler)
|
||||
tabClickedEvent.Event:connect(tabClickHandler)
|
||||
searchRequestedEvent.Event:connect(showSearchGear)
|
||||
|
||||
recalculateScrollLoadout()
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
--rbxassetid%872%
|
||||
-- Responsible for giving out tools in personal servers
|
||||
|
||||
-- first, lets see if buildTools have already been created
|
||||
-- create the object in lighting (TODO: move to some sort of "container" object when we have one)
|
||||
local toolsArray = game.Lighting:FindFirstChild("BuildToolsModel")
|
||||
local ownerArray = game.Lighting:FindFirstChild("OwnerToolsModel")
|
||||
local hasBuildTools = false
|
||||
|
||||
function getIds(idTable, assetTable)
|
||||
for i = 1, #idTable do
|
||||
local model = game:GetService("InsertService"):LoadAsset(idTable[i])
|
||||
if model then
|
||||
local children = model:GetChildren()
|
||||
for i = 1, #children do
|
||||
if children[i]:IsA("Tool") then
|
||||
table.insert(assetTable,children[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function storeInLighting(modelName, assetTable)
|
||||
local model = Instance.new("Model")
|
||||
model.Archivable = false
|
||||
model.Name = modelName
|
||||
|
||||
for i = 1, #assetTable do
|
||||
assetTable[i].Parent = model
|
||||
end
|
||||
|
||||
if not game.Lighting:FindFirstChild(modelName) then -- no one beat us to it, we get to insert
|
||||
model.Parent = game.Lighting
|
||||
end
|
||||
end
|
||||
|
||||
if not toolsArray then -- no one has made build tools yet, we get to!
|
||||
local buildToolIds = {}
|
||||
local ownerToolIds = {}
|
||||
|
||||
table.insert(buildToolIds,73089166) -- PartSelectionTool
|
||||
table.insert(buildToolIds,73089190) -- DeleteTool
|
||||
table.insert(buildToolIds,73089204) -- CloneTool
|
||||
table.insert(buildToolIds,73089214) -- RotateTool
|
||||
table.insert(buildToolIds,73089239) -- ConfigTool
|
||||
table.insert(buildToolIds,73089259) -- WiringTool
|
||||
table.insert(buildToolIds,58921588) -- ClassicTool
|
||||
|
||||
table.insert(ownerToolIds, 65347268)
|
||||
|
||||
-- next, create array of our tools
|
||||
local buildTools = {}
|
||||
local ownerTools = {}
|
||||
|
||||
getIds(buildToolIds, buildTools)
|
||||
getIds(ownerToolIds, ownerTools)
|
||||
|
||||
storeInLighting("BuildToolsModel",buildTools)
|
||||
storeInLighting("OwnerToolsModel",ownerTools)
|
||||
|
||||
toolsArray = game.Lighting:FindFirstChild("BuildToolsModel")
|
||||
ownerArray = game.Lighting:FindFirstChild("OwnerToolsModel")
|
||||
end
|
||||
|
||||
local localBuildTools = {}
|
||||
|
||||
function giveBuildTools()
|
||||
if not hasBuildTools then
|
||||
hasBuildTools = true
|
||||
local theTools = toolsArray:GetChildren()
|
||||
for i = 1, #theTools do
|
||||
local toolClone = theTools[i]:clone()
|
||||
if toolClone then
|
||||
toolClone.Parent = game.Players.LocalPlayer.Backpack
|
||||
table.insert(localBuildTools,toolClone)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function giveOwnerTools()
|
||||
local theOwnerTools = ownerArray:GetChildren()
|
||||
for i = 1, #theOwnerTools do
|
||||
local ownerToolClone = theOwnerTools[i]:clone()
|
||||
if ownerToolClone then
|
||||
ownerToolClone.Parent = game.Players.LocalPlayer.Backpack
|
||||
table.insert(localBuildTools,ownerToolClone)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function removeBuildTools()
|
||||
if hasBuildTools then
|
||||
hasBuildTools = false
|
||||
for i = 1, #localBuildTools do
|
||||
localBuildTools[i].Parent = nil
|
||||
end
|
||||
localBuildTools = {}
|
||||
end
|
||||
end
|
||||
|
||||
if game.Players.LocalPlayer.HasBuildTools then
|
||||
giveBuildTools()
|
||||
end
|
||||
if game.Players.LocalPlayer.PersonalServerRank >= 255 then
|
||||
giveOwnerTools()
|
||||
end
|
||||
|
||||
local debounce = false
|
||||
game.Players.LocalPlayer.Changed:connect(function(prop)
|
||||
if prop == "HasBuildTools" then
|
||||
while debounce do
|
||||
wait(0.5)
|
||||
end
|
||||
|
||||
debounce = true
|
||||
|
||||
if game.Players.LocalPlayer.HasBuildTools then
|
||||
giveBuildTools()
|
||||
else
|
||||
removeBuildTools()
|
||||
end
|
||||
|
||||
if game.Players.LocalPlayer.PersonalServerRank >= 255 then
|
||||
giveOwnerTools()
|
||||
end
|
||||
|
||||
debounce = false
|
||||
elseif prop == "PersonalServerRank" then
|
||||
if game.Players.LocalPlayer.PersonalServerRank >= 255 then
|
||||
giveOwnerTools()
|
||||
elseif game.Players.LocalPlayer.PersonalServerRank <= 0 then
|
||||
game.Players.LocalPlayer:Remove() -- you're banned, goodbye!
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
game.Players.LocalPlayer.CharacterAdded:connect(function()
|
||||
hasBuildTools = false
|
||||
if game.Players.LocalPlayer.HasBuildTools then
|
||||
giveBuildTools()
|
||||
end
|
||||
if game.Players.LocalPlayer.PersonalServerRank >= 255 then
|
||||
giveOwnerTools()
|
||||
end
|
||||
end)
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
--rbxassetid%873%
|
||||
-- ContextActionTouch.lua
|
||||
-- Copyright ROBLOX 2014, created by Ben Tkacheff
|
||||
-- this script controls ui and firing of lua functions that are bound in ContextActionService for touch inputs
|
||||
-- Essentially a user can bind a lua function to a key code, input type (mousebutton1 etc.) and this
|
||||
|
||||
-- Variables
|
||||
local contextActionService = Game:GetService("ContextActionService")
|
||||
local isTouchDevice = Game:GetService("UserInputService").TouchEnabled
|
||||
local functionTable = {}
|
||||
local buttonVector = {}
|
||||
local buttonScreenGui = nil
|
||||
local buttonFrame = nil
|
||||
|
||||
local ContextDownImage = "http://www.mete0r.xyz/asset/?id=97166756"
|
||||
local ContextUpImage = "http://www.mete0r.xyz/asset/?id=97166444"
|
||||
|
||||
local oldTouches = {}
|
||||
|
||||
local buttonPositionTable = {
|
||||
[1] = UDim2.new(0,123,0,70),
|
||||
[2] = UDim2.new(0,30,0,60),
|
||||
[3] = UDim2.new(0,180,0,160),
|
||||
[4] = UDim2.new(0,85,0,-25),
|
||||
[5] = UDim2.new(0,185,0,-25),
|
||||
[6] = UDim2.new(0,185,0,260),
|
||||
[7] = UDim2.new(0,216,0,65)
|
||||
}
|
||||
local maxButtons = #buttonPositionTable
|
||||
|
||||
-- Preload images
|
||||
Game:GetService("ContentProvider"):Preload(ContextDownImage)
|
||||
Game:GetService("ContentProvider"):Preload(ContextUpImage)
|
||||
|
||||
while not Game.Players do
|
||||
wait()
|
||||
end
|
||||
|
||||
while not Game.Players.LocalPlayer do
|
||||
wait()
|
||||
end
|
||||
|
||||
function createContextActionGui()
|
||||
if not buttonScreenGui and isTouchDevice then
|
||||
buttonScreenGui = Instance.new("ScreenGui")
|
||||
buttonScreenGui.Name = "ContextActionGui"
|
||||
|
||||
buttonFrame = Instance.new("Frame")
|
||||
buttonFrame.BackgroundTransparency = 1
|
||||
buttonFrame.Size = UDim2.new(0.3,0,0.5,0)
|
||||
buttonFrame.Position = UDim2.new(0.7,0,0.5,0)
|
||||
buttonFrame.Name = "ContextButtonFrame"
|
||||
buttonFrame.Parent = buttonScreenGui
|
||||
end
|
||||
end
|
||||
|
||||
-- functions
|
||||
function setButtonSizeAndPosition(object)
|
||||
local buttonSize = 55
|
||||
local xOffset = 10
|
||||
local yOffset = 95
|
||||
|
||||
-- todo: better way to determine mobile sized screens
|
||||
local onSmallScreen = (game.CoreGui.RobloxGui.AbsoluteSize.X < 600)
|
||||
if not onSmallScreen then
|
||||
buttonSize = 85
|
||||
xOffset = 40
|
||||
end
|
||||
|
||||
object.Size = UDim2.new(0,buttonSize,0,buttonSize)
|
||||
end
|
||||
|
||||
function contextButtonDown(button, inputObject, actionName)
|
||||
if inputObject.UserInputType == Enum.UserInputType.Touch then
|
||||
button.Image = ContextDownImage
|
||||
contextActionService:CallFunction(actionName, Enum.UserInputState.Begin, inputObject)
|
||||
end
|
||||
end
|
||||
|
||||
function contextButtonMoved(button, inputObject, actionName)
|
||||
if inputObject.UserInputType == Enum.UserInputType.Touch then
|
||||
button.Image = ContextDownImage
|
||||
contextActionService:CallFunction(actionName, Enum.UserInputState.Change, inputObject)
|
||||
end
|
||||
end
|
||||
|
||||
function contextButtonUp(button, inputObject, actionName)
|
||||
button.Image = ContextUpImage
|
||||
if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.End then
|
||||
contextActionService:CallFunction(actionName, Enum.UserInputState.End, inputObject)
|
||||
end
|
||||
end
|
||||
|
||||
function isSmallScreenDevice()
|
||||
return Game:GetService("GuiService"):GetScreenResolution().y <= 320
|
||||
end
|
||||
|
||||
|
||||
function createNewButton(actionName, functionInfoTable)
|
||||
local contextButton = Instance.new("ImageButton")
|
||||
contextButton.Name = "ContextActionButton"
|
||||
contextButton.BackgroundTransparency = 1
|
||||
contextButton.Size = UDim2.new(0,90,0,90)
|
||||
contextButton.Active = true
|
||||
if isSmallScreenDevice() then
|
||||
contextButton.Size = UDim2.new(0,70,0,70)
|
||||
end
|
||||
contextButton.Image = ContextUpImage
|
||||
contextButton.Parent = buttonFrame
|
||||
|
||||
local currentButtonTouch = nil
|
||||
|
||||
Game:GetService("UserInputService").InputEnded:connect(function ( inputObject )
|
||||
oldTouches[inputObject] = nil
|
||||
end)
|
||||
contextButton.InputBegan:connect(function(inputObject)
|
||||
if oldTouches[inputObject] then return end
|
||||
|
||||
if inputObject.UserInputState == Enum.UserInputState.Begin and currentButtonTouch == nil then
|
||||
currentButtonTouch = inputObject
|
||||
contextButtonDown(contextButton, inputObject, actionName)
|
||||
end
|
||||
end)
|
||||
contextButton.InputChanged:connect(function(inputObject)
|
||||
if oldTouches[inputObject] then return end
|
||||
if currentButtonTouch ~= inputObject then return end
|
||||
|
||||
contextButtonMoved(contextButton, inputObject, actionName)
|
||||
end)
|
||||
contextButton.InputEnded:connect(function(inputObject)
|
||||
if oldTouches[inputObject] then return end
|
||||
if currentButtonTouch ~= inputObject then return end
|
||||
|
||||
currentButtonTouch = nil
|
||||
oldTouches[inputObject] = true
|
||||
contextButtonUp(contextButton, inputObject, actionName)
|
||||
end)
|
||||
|
||||
local actionIcon = Instance.new("ImageLabel")
|
||||
actionIcon.Name = "ActionIcon"
|
||||
actionIcon.Position = UDim2.new(0.175, 0, 0.175, 0)
|
||||
actionIcon.Size = UDim2.new(0.65, 0, 0.65, 0)
|
||||
actionIcon.BackgroundTransparency = 1
|
||||
if functionInfoTable["image"] and type(functionInfoTable["image"]) == "string" then
|
||||
actionIcon.Image = functionInfoTable["image"]
|
||||
end
|
||||
actionIcon.Parent = contextButton
|
||||
|
||||
local actionTitle = Instance.new("TextLabel")
|
||||
actionTitle.Name = "ActionTitle"
|
||||
actionTitle.Size = UDim2.new(1,0,1,0)
|
||||
actionTitle.BackgroundTransparency = 1
|
||||
actionTitle.Font = Enum.Font.SourceSansBold
|
||||
actionTitle.TextColor3 = Color3.new(1,1,1)
|
||||
actionTitle.TextStrokeTransparency = 0
|
||||
actionTitle.FontSize = Enum.FontSize.Size18
|
||||
actionTitle.TextWrapped = true
|
||||
actionTitle.Text = ""
|
||||
if functionInfoTable["title"] and type(functionInfoTable["title"]) == "string" then
|
||||
actionTitle.Text = functionInfoTable["title"]
|
||||
end
|
||||
actionTitle.Parent = contextButton
|
||||
|
||||
return contextButton
|
||||
end
|
||||
|
||||
function createButton( actionName, functionInfoTable )
|
||||
local button = createNewButton(actionName, functionInfoTable)
|
||||
|
||||
local position = nil
|
||||
for i = 1,#buttonVector do
|
||||
if buttonVector[i] == "empty" then
|
||||
position = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not position then
|
||||
position = #buttonVector + 1
|
||||
end
|
||||
|
||||
if position > maxButtons then
|
||||
return -- todo: let user know we have too many buttons already?
|
||||
end
|
||||
|
||||
buttonVector[position] = button
|
||||
functionTable[actionName]["button"] = button
|
||||
|
||||
button.Position = buttonPositionTable[position]
|
||||
button.Parent = buttonFrame
|
||||
|
||||
if buttonScreenGui and buttonScreenGui.Parent == nil then
|
||||
buttonScreenGui.Parent = Game.Players.LocalPlayer.PlayerGui
|
||||
end
|
||||
end
|
||||
|
||||
function removeAction(actionName)
|
||||
if not functionTable[actionName] then return end
|
||||
|
||||
local actionButton = functionTable[actionName]["button"]
|
||||
|
||||
if actionButton then
|
||||
actionButton.Parent = nil
|
||||
|
||||
for i = 1,#buttonVector do
|
||||
if buttonVector[i] == actionButton then
|
||||
buttonVector[i] = "empty"
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
actionButton:Destroy()
|
||||
end
|
||||
|
||||
functionTable[actionName] = nil
|
||||
end
|
||||
|
||||
function addAction(actionName,createTouchButton,functionInfoTable)
|
||||
if functionTable[actionName] then
|
||||
removeAction(actionName)
|
||||
end
|
||||
functionTable[actionName] = {functionInfoTable}
|
||||
if createTouchButton and isTouchDevice then
|
||||
createContextActionGui()
|
||||
createButton(actionName, functionInfoTable)
|
||||
end
|
||||
end
|
||||
|
||||
-- Connections
|
||||
contextActionService.BoundActionChanged:connect( function(actionName, changeName, changeTable)
|
||||
if functionTable[actionName] and changeTable then
|
||||
local button = functionTable[actionName]["button"]
|
||||
if button then
|
||||
if changeName == "image" then
|
||||
button.ActionIcon.Image = changeTable[changeName]
|
||||
elseif changeName == "title" then
|
||||
button.ActionTitle.Text = changeTable[changeName]
|
||||
elseif changeName == "description" then
|
||||
-- todo: add description to menu
|
||||
elseif changeName == "position" then
|
||||
button.Position = changeTable[changeName]
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
contextActionService.BoundActionAdded:connect( function(actionName, createTouchButton, functionInfoTable)
|
||||
addAction(actionName, createTouchButton, functionInfoTable)
|
||||
end)
|
||||
|
||||
contextActionService.BoundActionRemoved:connect( function(actionName, functionInfoTable)
|
||||
removeAction(actionName)
|
||||
end)
|
||||
|
||||
contextActionService.GetActionButtonEvent:connect( function(actionName)
|
||||
if functionTable[actionName] then
|
||||
contextActionService:FireActionButtonFoundSignal(actionName, functionTable[actionName]["button"])
|
||||
end
|
||||
end)
|
||||
|
||||
-- make sure any bound data before we setup connections is handled
|
||||
local boundActions = contextActionService:GetAllBoundActionInfo()
|
||||
for actionName, actionData in pairs(boundActions) do
|
||||
addAction(actionName,actionData["createTouchButton"],actionData)
|
||||
end
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
--rbxassetid%875%
|
||||
local t = {}
|
||||
|
||||
t.Foo =
|
||||
function()
|
||||
print("foo")
|
||||
end
|
||||
|
||||
t.Bar =
|
||||
function()
|
||||
print("bar")
|
||||
end
|
||||
|
||||
t.Help =
|
||||
function(funcNameOrFunc)
|
||||
--input argument can be a string or a function. Should return a description (of arguments and expected side effects)
|
||||
if funcNameOrFunc == "Foo" or funcNameOrFunc == t.Foo then
|
||||
return "Function Foo. Arguments: None. Side effect: prints foo"
|
||||
elseif funcNameOrFunc == "Bar" or funcNameOrFunc == t.Bar then
|
||||
return "Function Bar. Arguments: None. Side effect: prints bar"
|
||||
end
|
||||
end
|
||||
|
||||
return t
|
||||
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
|
@ -0,0 +1,10 @@
|
|||
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
|
||||
<External>null</External>
|
||||
<External>nil</External>
|
||||
<Item class="StringValue" referent="RBX0">
|
||||
<Properties>
|
||||
<string name="Name">ScriptHashWhitelist</string>
|
||||
<string name="Value">b3f0342949bc9635e34e278c04d6fd90;1cb5c76965c37c216582cee7e1433262;4c6721f4bea2341a4d4a684c7f966d90;8e56422fe1414961d2edff32f944bf92;786406a29a6e8490cb266c06201aa92e;b3ac4e73d3733a57dea03d692aa26e34;a53eba1de89dbfdb80b3254ee388531d;d15e92a3f0fc1e66cf41a5d73cebb840;f1dfdef5f37e69ddd3fd6333f26e88c8;433d57e8472a8a870e274598229a93d4;f5221aae14307e3bcb1a5d154c5ef2f5;5e18b9ddf23c4f03c0fd00ee9f74a6e8;e84848af1e7a5ef61fccd70017a1499c;ee2fda1680f29d1e15e9d70f9d061df3;a30f58b57cb09ac1655cde37c750b02b;8ee09525290e5fd8b1d7d90ff4e08772;;d39de7b8e14666fafed115fcac1bd42a;f9a3b2366970250006eb5871718d1386;d46bd2f63d3743df0d65fba0026b1b3e;79edcc2cec0a91fd1ba03de301277bf9;cae4b54d5a33a04fcc08b71a4910aa98;3a6bbcd590fb50a1ab2c96d4c5381354;047683e14c39fb0726d37978027e7e41;60fcf891d61f15810f7fc1fbc306085a;85da2a691ca195ba0c8b727be3708854;ab1d7c5bd750ad0445c5468199ba01c7;111a198bfda686f90c974c4bd51b0bbb;6b0f7786df852254ad76584baf51f8a7;aa5868b23b2df1bd213fc34f55daf17b;50fcb8a21a10b8125d4573eaf71318ad;c0a7d6ca6e952ec6ebcc37002cb8b290;9b726d1c7771bc42aa03175c6c8a43d0;9b726d1c7771bc42aa03175c6c8a43d0;f10d555101c69e7bc5445b363865835e;4a143d0239140a90a111a3f316ee3349;f52510d8205181ca455a559ec153be7acaa15d93952e7366992e31df5af18441;3fa1b59b140c7babcb10b61b186020ad;1ab108f066289efd10a903744e2d3fe1;fabd28d867d693e3e465703956169f81;22dbbfb129b56c2f44ed52daa5ae1739;eeaadc007ef349e545ea6cd8295ad541;7bb0d01aea154912c3200cf964766fd4;84bf56ebe05f1f5c78a7a9c4cad52f74;bf3cda0e4a61be31f3e628d60d409a84;3987ae32127e39d9a7703b024f931bcf;9a53dc1d8a18035c7500513833761fa9;66c6d6dcf60ba2cceb8a9e613587ca6b;dbae0bffeb10d9f2152d87d94db62496;89254cffbaa0282d6e5971c2a8c09e55;46cbe9b2a510f6257a7eac135aad5651;8b56bcdc48551aff9edeabae48d5141c;ff58e3a4e3f0e514ad0b6258432f4fcd;89254cffbaa0282d6e5971c2a8c09e55;0321b9659210929462de367df55322bb;1b011d0e9868c56338b00fc891895fc1;6c52a6ca7f539564dc7c0a4eb3969eeb;2c7a8324161637f30405729b19885573;92b59508c397fcb6086f287ebd1ea3cd;90846a9269ae1b0bada8b205d156cfc0;2f5206f708e95f55bbb1ea712267445b;0276a5c631983f84e676a6162dad4a11;b5c2f8dea2ab79fafa1139aa22e70588;193dcfdb1e760c52c4573873a441deab;0276a5c631983f84e676a6162dad4a11;</string>
|
||||
</Properties>
|
||||
</Item>
|
||||
</roblox>
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
<roblox xmlns:xmime="http://www.w3.org/2005/05/xmlmime" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.roblox.com/roblox.xsd" version="4">
|
||||
<External>null</External>
|
||||
<External>nil</External>
|
||||
<Item class="Accessory" referent="RBX40EB0EE89F4D466ABD52DB61A5D1F382">
|
||||
<Properties>
|
||||
<CoordinateFrame name="AttachmentPoint">
|
||||
<X>0</X>
|
||||
<Y>-0.899999976</Y>
|
||||
<Z>0</Z>
|
||||
<R00>1</R00>
|
||||
<R01>0</R01>
|
||||
<R02>0</R02>
|
||||
<R10>-0</R10>
|
||||
<R11>0.980580688</R11>
|
||||
<R12>0.196116135</R12>
|
||||
<R20>0</R20>
|
||||
<R21>-0.196116135</R21>
|
||||
<R22>0.980580688</R22>
|
||||
</CoordinateFrame>
|
||||
<string name="Name">TrafficCone</string>
|
||||
</Properties>
|
||||
<Item class="Part" referent="RBX80C8F19E519F4AE4BA18BA09DDE63F99">
|
||||
<Properties>
|
||||
<bool name="Anchored">false</bool>
|
||||
<float name="BackParamA">-0.5</float>
|
||||
<float name="BackParamB">0.5</float>
|
||||
<token name="BackSurface">0</token>
|
||||
<token name="BackSurfaceInput">0</token>
|
||||
<float name="BottomParamA">-0.5</float>
|
||||
<float name="BottomParamB">0.5</float>
|
||||
<token name="BottomSurface">0</token>
|
||||
<token name="BottomSurfaceInput">0</token>
|
||||
<int name="BrickColor">194</int>
|
||||
<CoordinateFrame name="CFrame">
|
||||
<X>-3.73503828</X>
|
||||
<Y>6.53157806</Y>
|
||||
<Z>-29.3164387</Z>
|
||||
<R00>-0.916252911</R00>
|
||||
<R01>-0.0785642341</R01>
|
||||
<R02>-0.392821193</R02>
|
||||
<R10>-3.90117441e-021</R10>
|
||||
<R11>0.980580688</R11>
|
||||
<R12>-0.196116135</R12>
|
||||
<R20>0.400600582</R20>
|
||||
<R21>-0.179691985</R21>
|
||||
<R22>-0.898459911</R22>
|
||||
</CoordinateFrame>
|
||||
<bool name="CanCollide">true</bool>
|
||||
<PhysicalProperties name="CustomPhysicalProperties">
|
||||
<CustomPhysics>false</CustomPhysics>
|
||||
</PhysicalProperties>
|
||||
<float name="Elasticity">0.5</float>
|
||||
<float name="Friction">0.300000012</float>
|
||||
<float name="FrontParamA">-0.5</float>
|
||||
<float name="FrontParamB">0.5</float>
|
||||
<token name="FrontSurface">0</token>
|
||||
<token name="FrontSurfaceInput">0</token>
|
||||
<float name="LeftParamA">-0.5</float>
|
||||
<float name="LeftParamB">0.5</float>
|
||||
<token name="LeftSurface">0</token>
|
||||
<token name="LeftSurfaceInput">0</token>
|
||||
<bool name="Locked">true</bool>
|
||||
<token name="Material">256</token>
|
||||
<string name="Name">Handle</string>
|
||||
<float name="Reflectance">0</float>
|
||||
<float name="RightParamA">-0.5</float>
|
||||
<float name="RightParamB">0.5</float>
|
||||
<token name="RightSurface">0</token>
|
||||
<token name="RightSurfaceInput">0</token>
|
||||
<Vector3 name="RotVelocity">
|
||||
<X>-2.42862883e-023</X>
|
||||
<Y>3.62439101e-022</Y>
|
||||
<Z>-1.39473558e-023</Z>
|
||||
</Vector3>
|
||||
<float name="TopParamA">-0.5</float>
|
||||
<float name="TopParamB">0.5</float>
|
||||
<token name="TopSurface">0</token>
|
||||
<token name="TopSurfaceInput">0</token>
|
||||
<float name="Transparency">0</float>
|
||||
<Vector3 name="Velocity">
|
||||
<X>3.64650682e-020</X>
|
||||
<Y>0.0075033661</Y>
|
||||
<Z>3.64295609e-020</Z>
|
||||
</Vector3>
|
||||
<token name="formFactorRaw">2</token>
|
||||
<token name="shape">1</token>
|
||||
<Vector3 name="size">
|
||||
<X>1</X>
|
||||
<Y>2</Y>
|
||||
<Z>1</Z>
|
||||
</Vector3>
|
||||
</Properties>
|
||||
<Item class="SpecialMesh" referent="RBXFF501D4CA99545D19E44541183F2557C">
|
||||
<Properties>
|
||||
<token name="LODX">2</token>
|
||||
<token name="LODY">2</token>
|
||||
<Content name="MeshId"><url>http://www.roblox.com/asset/?id=1082802</url></Content>
|
||||
<token name="MeshType">5</token>
|
||||
<string name="Name">Mesh</string>
|
||||
<Vector3 name="Offset">
|
||||
<X>0</X>
|
||||
<Y>0</Y>
|
||||
<Z>0</Z>
|
||||
</Vector3>
|
||||
<Vector3 name="Scale">
|
||||
<X>1</X>
|
||||
<Y>1</Y>
|
||||
<Z>1</Z>
|
||||
</Vector3>
|
||||
<Content name="TextureId"><url>http://www.roblox.com/asset/?id=1082804</url></Content>
|
||||
<Vector3 name="VertexColor">
|
||||
<X>1</X>
|
||||
<Y>1</Y>
|
||||
<Z>1</Z>
|
||||
</Vector3>
|
||||
</Properties>
|
||||
</Item>
|
||||
<Item class="Attachment" referent="RBX548E200376104FAEB962EB83D354E04D">
|
||||
<Properties>
|
||||
<CoordinateFrame name="CFrame">
|
||||
<X>8.65838956e-009</X>
|
||||
<Y>-0.801995277</Y>
|
||||
<Z>-0.0198786259</Z>
|
||||
<R00>1</R00>
|
||||
<R01>7.8713791e-009</R01>
|
||||
<R02>-5.01820807e-014</R02>
|
||||
<R10>-7.71851205e-009</R10>
|
||||
<R11>0.980580688</R11>
|
||||
<R12>0.196116135</R12>
|
||||
<R20>1.54375357e-009</R20>
|
||||
<R21>-0.196116135</R21>
|
||||
<R22>0.980580688</R22>
|
||||
</CoordinateFrame>
|
||||
<string name="Name">HatAttachment</string>
|
||||
<bool name="Visible">false</bool>
|
||||
</Properties>
|
||||
</Item>
|
||||
</Item>
|
||||
</Item>
|
||||
</roblox>
|
||||
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -0,0 +1,66 @@
|
|||
-- This is the thumbnail script for R6 avatars. Straight up and down, with the right arm out if they have a gear.
|
||||
local asset = 0
|
||||
local baseurl = "http://mete0r.xyz" -- have to set to https for production
|
||||
local HttpService = game:GetService("HttpService")
|
||||
HttpService.HttpEnabled = true
|
||||
|
||||
---@diagnostic disable-next-line: invalid-class-name
|
||||
local ThumbnailGenerator = game:GetService("ThumbnailGenerator")
|
||||
|
||||
pcall(function() game:GetService("ContentProvider"):SetBaseUrl(baseurl) end)
|
||||
game:GetService("InsertService"):SetBaseSetsUrl(baseurl .. "/Game/Tools/InsertAsset.ashx?nsets=10&type=base")
|
||||
game:GetService("InsertService"):SetUserSetsUrl(baseurl .. "/Game/Tools/InsertAsset.ashx?nsets=20&type=user&userid=%d")
|
||||
game:GetService("InsertService"):SetCollectionUrl(baseurl .. "/Game/Tools/InsertAsset.ashx?sid=%d")
|
||||
game:GetService("InsertService"):SetAssetUrl(baseurl .. "/Asset/?id=%d")
|
||||
game:GetService("InsertService"):SetAssetVersionUrl(baseurl .. "/Asset/?assetversionid=%d")
|
||||
---@diagnostic disable-next-line: invalid-class-name
|
||||
pcall(function() game:GetService("ScriptInformationProvider"):SetAssetUrl(url .. "/Asset/") end)
|
||||
|
||||
game:GetService("ScriptContext").ScriptsDisabled = true
|
||||
|
||||
thing = game:GetService("InsertService"):LoadAsset(asset)
|
||||
if thing:GetChildren()[1]:IsA("Shirt") or thing:GetChildren()[1]:IsA("Pants") then
|
||||
local player = game:GetService("Players"):CreateLocalPlayer(0)
|
||||
player:LoadCharacter()
|
||||
thing:GetChildren()[1].Parent = player.Character
|
||||
bcolor = Instance.new("BodyColors", player.Character)
|
||||
bcolor.HeadColor = BrickColor.new(1001)
|
||||
bcolor.TorsoColor = BrickColor.new(1001)
|
||||
bcolor.LeftArmColor = BrickColor.new(1001)
|
||||
bcolor.RightArmColor = BrickColor.new(1001)
|
||||
bcolor.LeftLegColor = BrickColor.new(1001)
|
||||
bcolor.RightLegColor = BrickColor.new(1001)
|
||||
elseif thing:GetChildren()[1]:IsA("Decal") then
|
||||
local player = game:GetService("Players"):CreateLocalPlayer(0)
|
||||
player:LoadCharacter()
|
||||
player.Character.Head.face:Destroy()
|
||||
thing:GetChildren()[1].Parent = player.Character.Head
|
||||
bcolor = Instance.new("BodyColors", player.Character)
|
||||
bcolor.HeadColor = BrickColor.new(1001)
|
||||
bcolor.TorsoColor = BrickColor.new(1001)
|
||||
bcolor.LeftArmColor = BrickColor.new(1001)
|
||||
bcolor.RightArmColor = BrickColor.new(1001)
|
||||
bcolor.LeftLegColor = BrickColor.new(1001)
|
||||
bcolor.RightLegColor = BrickColor.new(1001)
|
||||
|
||||
for _, child in pairs(player.Character:GetChildren()) do
|
||||
if child.Name ~= "Head" and child:IsA("BasePart") then
|
||||
child:Destroy()
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
thing.Parent = game.workspace
|
||||
end
|
||||
|
||||
local arguments = {
|
||||
["thumbnail"] = ThumbnailGenerator:Click("PNG", 400, 400, --[[hideSky = ]] true),
|
||||
["asset"] = asset
|
||||
}
|
||||
|
||||
HttpService:PostAsync(
|
||||
baseurl .. "/api/thumbnailrender/rccasset",
|
||||
HttpService:JSONEncode(arguments)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
7c9f615b-8535-4e9c-96d0-dff4cecabdd1
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
const jwt = require('jsonwebtoken')
|
||||
require('dotenv').config()
|
||||
const JWT_SECRET = process.env.JWT_SECRET
|
||||
const atob = require("atob");
|
||||
const model = require("./../model/user.js")
|
||||
|
||||
const requireAuth = (req,res,next) => {
|
||||
if (!req.cookies && req.headers['authorization']) {
|
||||
return res.json({status: "error", error: "Unauthorized"})
|
||||
}
|
||||
let token = req.cookies.jwt??req.cookies['.ROBLOSECURITY']??req.headers['authorization']??req.headers['roblox-session-id']
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({status: "error", error: "Unauthorized"})
|
||||
}
|
||||
|
||||
|
||||
jwt.verify(token,JWT_SECRET, (err,decodedtoken) => {
|
||||
if (err){
|
||||
res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
|
||||
return res.status(401).json({status: "error", error: "Unauthorized"})
|
||||
}else{
|
||||
var tokendata = decodedtoken
|
||||
var name = tokendata.userid
|
||||
try {
|
||||
model.findOne({userid: name},async function(err, doc) {
|
||||
req.numberofcoins = doc.coins
|
||||
req.tokenData = tokendata
|
||||
req.userdocument = doc
|
||||
moderationstatus = JSON.parse(doc.moderation)
|
||||
const actualTimeMilliseconds = new Date().getTime()
|
||||
if (actualTimeMilliseconds - doc.timesincelastrequest >= 60000 * 1 || !doc.timesincelastrequest /*2 minutes make sure to update*/){
|
||||
doc.timesincelastrequest = actualTimeMilliseconds
|
||||
doc.markModified('timesincelastrequest')
|
||||
await doc.save()
|
||||
}
|
||||
// check if they are eligble for daily login reward
|
||||
if (actualTimeMilliseconds - req.userdocument.lastclaimofcurrency > 86400000){ // 24 hours
|
||||
req.userdocument.lastclaimofcurrency = actualTimeMilliseconds
|
||||
if (req.userdocument.membership === "TurboBuildersClub"){
|
||||
req.userdocument.coins += 90
|
||||
}else if (req.userdocument.membership === "BuildersClub"){
|
||||
req.userdocument.coins += 60
|
||||
}else if (req.userdocument.membership === "OutrageousBuildersClub"){
|
||||
req.userdocument.coins += 150
|
||||
}
|
||||
else{
|
||||
req.userdocument.coins += 35
|
||||
}
|
||||
req.userdocument.markModified('coins')
|
||||
req.userdocument.markModified('lastclaimofcurrency')
|
||||
await req.userdocument.save()
|
||||
}
|
||||
|
||||
if (moderationstatus.status !== "ok") {
|
||||
// if they are moderated then we invalidate the cookie and proceed
|
||||
//res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
|
||||
//return res.send("You have been moderated for "+moderationstatus.Reason+" expires at"+moderationstatus.ExpiresIn+" Moderated by "+moderationstatus.BannedBy )
|
||||
var date = Date.parse(moderationstatus.ExpiresIn)
|
||||
var datetime = new Date();
|
||||
var datetime2 = Date.parse(datetime)
|
||||
/*if (date <= datetime2){
|
||||
// they have served there time
|
||||
|
||||
model.updateOne({userid: doc.userid}, {
|
||||
$set: {
|
||||
moderation: JSON.stringify({"status":"ok","Reason":"none","ExpiresIn":"none", "BannedBy": "none"})
|
||||
}
|
||||
},
|
||||
function(err, doc) {
|
||||
//console.log(err)
|
||||
})
|
||||
return next()
|
||||
|
||||
}*/
|
||||
return res.json({status: "error", error:"Moderated", moderationstatus})
|
||||
}
|
||||
next()
|
||||
})/*.lean() rip*/}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {requireAuth}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
const jwt = require('jsonwebtoken')
|
||||
require('dotenv').config()
|
||||
const JWT_SECRET = process.env.JWT_SECRET
|
||||
const atob = require("atob");
|
||||
const model = require("./../model/user.js")
|
||||
// exactly the same as normal authimddleware but uses req.query instead of cookies for our client
|
||||
const requireAuth = (req,res,next) => {
|
||||
let token = req.query.auth
|
||||
if (req.cookies && req.headers?.['user-agent'] != "Roblox/WinInet") { // Mobile
|
||||
if (req.cookies.jwt) {
|
||||
token = req.cookies.jwt
|
||||
}
|
||||
}
|
||||
if (req.headers['roblox-session-id']) { // TeleportService
|
||||
token = req.headers['roblox-session-id']
|
||||
}
|
||||
if (req.headers?.['user-agent']?.includes("Android") === true || req.headers?.['user-agent']?.includes("iPhone") === true){
|
||||
console.log(token)
|
||||
console.log(req.headers)
|
||||
}
|
||||
//console.log(req.headers)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (!token) {
|
||||
return res.status(405).end()
|
||||
}
|
||||
|
||||
|
||||
jwt.verify(token,JWT_SECRET, (err,decodedtoken) => {
|
||||
if (err){
|
||||
res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
|
||||
return res.status(405)
|
||||
}else{
|
||||
var tokendata = decodedtoken
|
||||
var name = tokendata.userid
|
||||
try {
|
||||
model.findOne({userid: name}, function(err, doc) {
|
||||
req.numberofcoins = doc.coins
|
||||
req.tokenData = tokendata
|
||||
req.userdocument = doc
|
||||
moderationstatus = JSON.parse(doc.moderation)
|
||||
if (moderationstatus.status !== "ok") {
|
||||
// if they are moderated then we invalidate the cookie and proceed
|
||||
//res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
|
||||
//return res.send("You have been moderated for "+moderationstatus.Reason+" expires at"+moderationstatus.ExpiresIn+" Moderated by "+moderationstatus.BannedBy )
|
||||
var date = Date.parse(moderationstatus.ExpiresIn)
|
||||
var datetime = new Date();
|
||||
var datetime2 = Date.parse(datetime)
|
||||
/*if (date <= datetime2){
|
||||
// they have served there time
|
||||
|
||||
model.updateOne({userid: doc.userid}, {
|
||||
$set: {
|
||||
moderation: JSON.stringify({"status":"ok","Reason":"none","ExpiresIn":"none", "BannedBy": "none"})
|
||||
}
|
||||
},
|
||||
function(err, doc) {
|
||||
//console.log(err)
|
||||
})
|
||||
|
||||
|
||||
}*/
|
||||
return res.json({status: "error", error:"Moderated", moderationstatus})
|
||||
}
|
||||
next()
|
||||
})/*.lean() rip*/}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {requireAuth}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
const jwt = require('jsonwebtoken')
|
||||
require('dotenv').config()
|
||||
const JWT_SECRET = process.env.JWT_SECRET
|
||||
const atob = require("atob");
|
||||
const model = require("./../model/user.js")
|
||||
|
||||
const grabAuth = (req,res,next) => {
|
||||
if (!req.cookies && req.headers['authorization']) {
|
||||
return next()
|
||||
}
|
||||
const token = req.cookies.jwt??req.cookies['.ROBLOSECURITY']??req.headers['authorization']
|
||||
|
||||
if (!token) {
|
||||
return next()
|
||||
}
|
||||
|
||||
jwt.verify(token,JWT_SECRET, (err,decodedtoken) => {
|
||||
if (err){
|
||||
next()
|
||||
}else{
|
||||
var tokendata = decodedtoken
|
||||
var name = tokendata.username
|
||||
try {
|
||||
model.findOne({username: new RegExp('^'+name+'$', "i")}, function(err, doc) {
|
||||
req.numberofcoins = doc.coins
|
||||
req.admin = doc.admin
|
||||
req.tokenData = tokendata
|
||||
req.userdocument = doc
|
||||
moderationstatus = JSON.parse(doc.moderation)
|
||||
if (moderationstatus.status !== "ok") {
|
||||
// if they are moderated then we invalidate the cookie and proceed
|
||||
//res.cookie('jwt', "", {SameSite: "Strict",maxAge: 1 })
|
||||
//return res.send("You have been moderated for "+moderationstatus.Reason+" expires at"+moderationstatus.ExpiresIn+" Moderated by "+moderationstatus.BannedBy )
|
||||
var date = Date.parse(moderationstatus.ExpiresIn)
|
||||
var datetime = new Date();
|
||||
var datetime2 = Date.parse(datetime)
|
||||
if (date <= datetime2){
|
||||
// they have served there time
|
||||
|
||||
model.updateOne({userid: doc.userid}, {
|
||||
$set: {
|
||||
moderation: JSON.stringify({"status":"ok","Reason":"none","ExpiresIn":"none", "BannedBy": "none"})
|
||||
}
|
||||
},
|
||||
function(err, doc) {
|
||||
//console.log(err)
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
return res.json({status: "error", error:"Moderated", moderationstatus})
|
||||
}
|
||||
next()
|
||||
})/*.lean() rip*/}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {grabAuth}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
const requirediscord = (req,res,next) => {
|
||||
const discordid = req.userdocument.discordid
|
||||
if (!discordid) {
|
||||
return res.json({status: "error", error: "Discord link required for develop. Link your discord in the settings panel."})
|
||||
}else{
|
||||
next();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = {requirediscord}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
const mongoose = require('mongoose')
|
||||
const bankSchema = new mongoose.Schema({
|
||||
balance: {type: Number, required: true},
|
||||
},
|
||||
{collection: 'bank'}
|
||||
)
|
||||
const model = mongoose.model('bank', bankSchema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
const mongoose = require('mongoose')
|
||||
const CommentSchema = new mongoose.Schema({
|
||||
associatedassetid: {type: Number, required: true, index: true},
|
||||
associatedassettype: {type: String, required: true, index: true},
|
||||
posterid: {type: Number, required: true},
|
||||
content: {type: String, required: true},
|
||||
date: {type: Number, required: true},
|
||||
moderated: {type: Boolean, required: true}
|
||||
},
|
||||
{collection: 'comments'}
|
||||
)
|
||||
|
||||
CommentSchema.virtual('poster', {
|
||||
ref: 'UserSchema',
|
||||
localField: 'posterid',
|
||||
foreignField: 'userid',
|
||||
justOne: true
|
||||
})
|
||||
|
||||
const model = mongoose.model('CommentSchema', CommentSchema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
const mongoose = require('mongoose')
|
||||
const ConfigSchema = new mongoose.Schema({
|
||||
RegistrationEnabled: {type: Boolean, required: true},
|
||||
MaintenanceEnabled: {type: Boolean, required: true},
|
||||
KeysEnabled: {type: Boolean, required: true},
|
||||
GamesEnabled: {type: Boolean, required: true}
|
||||
},
|
||||
{collection: 'config'}
|
||||
)
|
||||
|
||||
const model = mongoose.model('ConfigSchema', ConfigSchema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
const mongoose = require('mongoose')
|
||||
const GamesSchema = new mongoose.Schema({
|
||||
useridofowner: {type: Number, required: true},
|
||||
idofgame: {type: Number, required: true, index: true},
|
||||
nameofgame: {type: String, required: true},
|
||||
numberofplayers: {type: String, required: true},
|
||||
descrption: {type: String, required: true},
|
||||
datastore: {type: String, required: false},
|
||||
visits: {type: Number, required: false},
|
||||
version: {type: String, required: true},
|
||||
featured: {type: Boolean, required: false},
|
||||
players: {type: Object, required: false},
|
||||
avatartype: {type: Object, required: false},
|
||||
gearallowed: {type: Boolean, required: false},
|
||||
comments: {type: Object, required: false}
|
||||
},
|
||||
{collection: 'games'}
|
||||
)
|
||||
|
||||
GamesSchema.virtual('owner', {
|
||||
ref: 'UserSchema',
|
||||
localField: 'useridofowner',
|
||||
foreignField: 'userid',
|
||||
justOne: true
|
||||
})
|
||||
|
||||
const model = mongoose.model('GamesSchema', GamesSchema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
const mongoose = require('mongoose')
|
||||
const GroupSchema = new mongoose.Schema({
|
||||
Name: {type: String, required: true},
|
||||
Description: {type: String, required: true},
|
||||
Public: {type: Boolean, required: true},
|
||||
IconApproved: {type: Boolean, required: true},
|
||||
denied: {type: Boolean, required: false},
|
||||
Hidden: {type: Boolean, required: false},
|
||||
groupid: {type: Number, required: true},
|
||||
ownerid : {type: Number, required: true},
|
||||
memberscount: {type: Number, required: true},
|
||||
members: {type: [{userId: Number, rank: Number}], required: true},
|
||||
currentshout: {type: {content: String, shouter: Number}, required: false},
|
||||
Roles: {type: [{RoleName: String, Permissions: {Shout: Boolean, Kick: Boolean, ChangeRoles: Boolean, ModerateWall: Boolean, ManageAllies: Boolean, All: Boolean}, Rank: Number}], required: true}, // default {}
|
||||
},
|
||||
{collection: 'groups'}
|
||||
)
|
||||
const model = mongoose.model('GroupSchema', GroupSchema)
|
||||
|
||||
GroupSchema.virtual('owner', {
|
||||
ref: 'UserSchema',
|
||||
localField: 'ownerid',
|
||||
foreignField: 'userid',
|
||||
justOne: true
|
||||
})
|
||||
|
||||
GroupSchema.virtual('memberspoly', {
|
||||
ref: 'UserSchema',
|
||||
localField: 'members.userId',
|
||||
foreignField: 'userid'
|
||||
})
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import { Schema } from 'redis-om'
|
||||
|
||||
const ipWhiteListSchema = new Schema('ipWhiteListSchema', {
|
||||
ip: { type: 'string' },
|
||||
})
|
||||
|
||||
export default ipWhiteListSchema
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
const mongoose = require('mongoose')
|
||||
const CatalogSchema = new mongoose.Schema({
|
||||
Name: {type: String, required: true},
|
||||
Description: {type: String, required: false},
|
||||
Price: {type: String, required: true},
|
||||
Type: {type: String, required: true},
|
||||
Creator: {type: Number, required: false},
|
||||
Hidden: {type: Boolean, required: false},
|
||||
ItemId: {type: String, required: true},
|
||||
Sales: {type: Number, required: false},
|
||||
ActiveAd: {type: Boolean, required: false}, // these 4 are for user generated ads
|
||||
adtype: {type: String, required: false},
|
||||
adredirectid: {type: String, required: false},
|
||||
adstartedtime: {type: Number, required: false},
|
||||
approved: {type: Boolean, required: true},
|
||||
denied: {type: Boolean, required: false},
|
||||
associatedgameid: {type: Number, required: false},
|
||||
},
|
||||
{collection: 'catalog'}
|
||||
)
|
||||
const model = mongoose.model('CatalogSchema', CatalogSchema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
const mongoose = require('mongoose')
|
||||
const KeysSchema = new mongoose.Schema({
|
||||
Creator: {type: String, required: true},
|
||||
Key: {type: String, required: true},
|
||||
Used: {type: Boolean, required: true},
|
||||
UsedBy: {type: String, required: false}
|
||||
},
|
||||
{collection: 'keys'}
|
||||
)
|
||||
|
||||
const model = mongoose.model('KeysSchema', KeysSchema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
const mongoose = require('mongoose')
|
||||
const RccSchema = new mongoose.Schema({
|
||||
PlaceId: {type: Number, required: true},
|
||||
Port: {type: Number, required: true},
|
||||
Status: {type: Number, required: true},
|
||||
},
|
||||
{collection: 'RCC'}
|
||||
)
|
||||
const model = mongoose.model('RccSchema', RccSchema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
const mongoose = require('mongoose')
|
||||
const Rcc2014Schema = new mongoose.Schema({
|
||||
PlaceId: {type: Number, required: true},
|
||||
Port: {type: Number, required: true}
|
||||
},
|
||||
{collection: 'RCC2014'}
|
||||
)
|
||||
const model = mongoose.model('Rcc2014Schema', Rcc2014Schema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
const mongoose = require('mongoose')
|
||||
const Rcc2018Schema = new mongoose.Schema({
|
||||
PlaceId: {type: Number, required: true},
|
||||
Port: {type: Number, required: true},
|
||||
Status: {type: Number, required: true},
|
||||
},
|
||||
{collection: 'RCC2018'}
|
||||
)
|
||||
const model = mongoose.model('Rcc2018Schema', Rcc2018Schema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
const mongoose = require('mongoose')
|
||||
const Rcc2020Schema = new mongoose.Schema({
|
||||
PlaceId: {type: Number, required: true},
|
||||
Port: {type: Number, required: true},
|
||||
Status: {type: Number, required: true},
|
||||
},
|
||||
{collection: 'RCC2020'}
|
||||
)
|
||||
const model = mongoose.model('Rcc2020Schema', Rcc2020Schema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
const mongoose = require('mongoose')
|
||||
var uniqueValidator = require('mongoose-unique-validator');
|
||||
const UserSchema = new mongoose.Schema({
|
||||
username: {type: String, required: true, unique: true,uniqueCaseInsensitive: true},
|
||||
password: {type: String, required: true},
|
||||
coins: {type: Number, required: true},
|
||||
admin: {type: Boolean, required: true},
|
||||
ugcpermission: {type: Boolean, required: false},
|
||||
userid: {type: Number, required: true, index: true},
|
||||
moderation: {type: String, required: true},
|
||||
moderationhistory: {type: Object, required: false},
|
||||
inventory: {type: Object, required: false},
|
||||
colors: {type: Object, required: false},
|
||||
joindate: {type: String, required: true},
|
||||
lastclaimofcurrency: {type: Number, required: true},
|
||||
discordid: {type: String, required: false},
|
||||
gamejoin: {type: String, required: false},
|
||||
gamejoin2018: {type: String, required: false},
|
||||
gamejoin2020: {type: String, required: false},
|
||||
twofasecrets: {type: String, required: false},
|
||||
followers: {type: Object, required: false},
|
||||
friends: {type: Object, required: false},
|
||||
friendrequests: {type: Object, required: false},
|
||||
membership: {type: String, required: true},
|
||||
badges: {type: Object, required: false},
|
||||
status: {type: String, required: false},
|
||||
timesincelastrequest: {type: Number, required: true},
|
||||
avatartype: {type: String, required: false},
|
||||
bio: {type: String, required: false},
|
||||
recentlyplayed: {type: [{id: Number}], required: false},
|
||||
css: {type: String, required: false},
|
||||
aboutme: {type: String, required: false},
|
||||
lastfeedsharetime: {type: Number, required: false},
|
||||
feed: [{posterid: Number, content: String, date: Number, moderated: Boolean}], required: false},
|
||||
|
||||
{collection: 'users'}
|
||||
)
|
||||
UserSchema.plugin(uniqueValidator)
|
||||
|
||||
UserSchema.virtual('recentlyplayedgames', {
|
||||
ref: 'GamesSchema',
|
||||
localField: 'recentlyplayed.id',
|
||||
foreignField: 'idofgame'
|
||||
})
|
||||
|
||||
UserSchema.virtual('friendsdata', {
|
||||
ref: 'UserSchema',
|
||||
localField: 'friends.userid',
|
||||
foreignField: 'userid'
|
||||
})
|
||||
|
||||
UserSchema.virtual('feed.userdata', {
|
||||
ref: 'UserSchema',
|
||||
localField: 'feed.posterid',
|
||||
foreignField: 'userid',
|
||||
justOne: true
|
||||
})
|
||||
|
||||
|
||||
const model = mongoose.model('UserSchema', UserSchema)
|
||||
|
||||
module.exports = model
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"name": "datastoreservice",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"devStart": "cross-env PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host nodemon server.mjs",
|
||||
"prod": "PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host pm2 start server.mjs",
|
||||
"prodreload": "PROTOCOL_HEADER=x-forwarded-proto HOST_HEADER=x-forwarded-host pm2 reload server.mjs"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mfd/rbxdatastoreservice": "^2.3.10",
|
||||
"@yaireo/relative-time": "^1.0.3",
|
||||
"atob": "^2.1.2",
|
||||
"bcrypt": "^5.0.1",
|
||||
"body-parser": "^1.20.0",
|
||||
"connect-flash": "^0.1.1",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"cors": "^2.8.5",
|
||||
"daisyui": "^2.24.2",
|
||||
"dotenv": "^16.0.1",
|
||||
"easy-soap-request": "^4.8.0",
|
||||
"esbuild": "0.17.4",
|
||||
"express": "^4.18.1",
|
||||
"express-flash-message": "^2.1.0",
|
||||
"express-prom-bundle": "^6.5.0",
|
||||
"express-rate-limit": "^6.7.0",
|
||||
"express-session": "^1.17.3",
|
||||
"file-type-checker": "^1.0.4",
|
||||
"get-port": "^6.1.2",
|
||||
"get-port-please": "^2.6.1",
|
||||
"helmet": "^5.1.1",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"mongo-sanitize": "^1.1.0",
|
||||
"mongoose": "^6.5.2",
|
||||
"mongoose-unique-validator": "^3.1.0",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-fetch": "^3.2.10",
|
||||
"png-validator": "^1.1.0",
|
||||
"prom-client": "^14.1.0",
|
||||
"qrcode": "^1.5.1",
|
||||
"redis": "^4.6.5",
|
||||
"redis-om": "^0.4.0-beta.3",
|
||||
"req-flash": "^0.0.3",
|
||||
"speakeasy": "^2.0.0",
|
||||
"xml-js": "^1.6.11",
|
||||
"xss": "^1.0.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
"nodemon": "^2.0.19"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
||||
let controller = new AbortController();
|
||||
require('dotenv').config()
|
||||
const RCC_HOST = process.env.RCC_HOST
|
||||
|
||||
const url = 'http://'+RCC_HOST+':64989'; // change this to rcc soap
|
||||
|
||||
var convert = require('xml-js');
|
||||
const sampleHeaders = {
|
||||
'Content-Type': 'text/xml;charset=UTF-8',
|
||||
};
|
||||
|
||||
|
||||
|
||||
async function OpenJob(jobid,script,expiration){
|
||||
return new Promise(async (resolve, reject) => {
|
||||
// this is all boilerplate because soap sucks
|
||||
var xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:ns1': 'http://roblox.com/'
|
||||
},
|
||||
'SOAP-ENV:Body': {
|
||||
'ns1:OpenJobEx': {
|
||||
'ns1:job': {
|
||||
'ns1:id': { _text: 'StringTest11' },
|
||||
'ns1:expirationInSeconds': { _text: '10' },
|
||||
'ns1:category': { _text: '0' },
|
||||
'ns1:cores': { _text: '1' }
|
||||
},
|
||||
'ns1:script': {
|
||||
'ns1:name': { _text: 'StringTest11-Script' },
|
||||
'ns1:script': {
|
||||
_text: 'print("Recieved job with ID " .. game.JobId)\r\n'
|
||||
},
|
||||
'ns1:arguments': {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobEx']['ns1:job']['ns1:id']._text = jobid
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobEx']['ns1:job']['ns1:expirationInSeconds']._text = expiration
|
||||
if (!expiration) {
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobEx']['ns1:job']['ns1:expirationInSeconds']._text = "60"
|
||||
}
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobEx']['ns1:script']['ns1:script']._text = script
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function GetAllJobs() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const xmlData = (xml = {
|
||||
_declaration: {
|
||||
_attributes: { version: '1.0', encoding: 'UTF - 8' },
|
||||
},
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
|
||||
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
|
||||
'xmlns:ns1': 'http://roblox.com/',
|
||||
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12',
|
||||
},
|
||||
'SOAP-ENV:Body': { 'ns1:GetAllJobsEx': {} },
|
||||
},
|
||||
})
|
||||
|
||||
const body = convert.js2xml(xmlData, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetAllJobsExResponse']['ns1:GetAllJobsExResult']
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
async function Execute(jobid,script) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
|
||||
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
|
||||
'xmlns:ns1': 'http://roblox.com/',
|
||||
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12'
|
||||
},
|
||||
'SOAP-ENV:Body': {
|
||||
'ns1:ExecuteEx': {
|
||||
'ns1:jobID': { _text: 'Test' },
|
||||
'ns1:script': {
|
||||
'ns1:name': { _text: 'Script' },
|
||||
'ns1:script': { _text: 'print("no")' },
|
||||
'ns1:arguments': { _text: '' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:ExecuteEx']['ns1:jobID']._text = jobid
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:ExecuteEx']['ns1:script']['ns1:script']._text = script
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
async function CloseJob(jobid) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
|
||||
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
|
||||
'xmlns:ns1': 'http://roblox.com/',
|
||||
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12'
|
||||
},
|
||||
'SOAP-ENV:Body': {
|
||||
'ns1:CloseJob': {
|
||||
'ns1:jobID': { _text: 'Test' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:CloseJob']['ns1:jobID']._text = jobid
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
async function RenewLease(jobid,expiration) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:ns1': 'http://roblox.com/',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance'
|
||||
},
|
||||
'SOAP-ENV:Body': {
|
||||
'ns1:RenewLease': {
|
||||
'ns1:jobID': {
|
||||
_attributes: { 'xsi:type': 'ns1:Job' },
|
||||
'ns1:id': { _text: 'StringTest11' },
|
||||
'ns1:expirationInSeconds': { _text: '10' },
|
||||
'ns1:category': { _text: '0' },
|
||||
'ns1:cores': { _text: '1' }
|
||||
},
|
||||
'ns1:expirationInSeconds': { _text: '100' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:RenewLease']['ns1:jobID']['ns1:id']._text = jobid
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:RenewLease']['ns1:expirationInSeconds']._text = expiration
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function GetExpiration(jobid){
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:ns1': 'http://roblox.com/'
|
||||
},
|
||||
'SOAP-ENV:Body': { 'ns1:GetExpiration': { 'ns1:jobID': { _text: 'Test' } } }
|
||||
}
|
||||
}
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetExpiration']['ns1:jobID']._text = jobid
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
//var gameservertxt = fs.readFileSync('actualgameserver.txt','utf-8')
|
||||
//gameservertxt = gameservertxt.replace('function start(placeId, port, url)','function start(1111, port)')
|
||||
|
||||
async function CloseExpiredJobs(){
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var xml = xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:ns1': 'http://roblox.com/'
|
||||
},
|
||||
'SOAP-ENV:Body': { 'ns1:CloseExpiredJobs': {} }
|
||||
}
|
||||
}
|
||||
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function CloseAllJobs(){
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var xml = xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:ns1': 'http://roblox.com/'
|
||||
},
|
||||
'SOAP-ENV:Body': { 'ns1:CloseAllJobs': {} }
|
||||
}
|
||||
}
|
||||
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
module.exports = {OpenJob, GetAllJobs,Execute,CloseJob,RenewLease,GetExpiration,CloseExpiredJobs,CloseAllJobs}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,300 @@
|
|||
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
||||
let controller = new AbortController();
|
||||
require('dotenv').config()
|
||||
const RCC_HOST = process.env.RCC_HOST
|
||||
var convert = require('xml-js');
|
||||
|
||||
let url = 'http://'+RCC_HOST+':8000'; // change this to rcc soap
|
||||
|
||||
async function OpenGame(jobid,port,ip,placeid,creatorid){
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let json = {"Mode":"GameServer","GameId":"game1","Settings":{"IsRobloxPlace":false,"PlaceId":1,"CreatorId":1,"GameId":"00000000-0000-0000-0000-000000000132","GsmInterval":50,"MaxPlayers":100,"MaxGameInstances":52,"ApiKey":"egg","GameCode":"AAAAAAAAAAAAAA-a","PreferredPlayerCapacity":10,"DatacenterId":1,"PlaceVisitAccessKey":"rbx_evt_ftp","UniverseId":13058,"PlaceFetchUrl":"https://mete0r.xyz/asset?id=11","MatchmakingContextId":1,"CreatorType":"User","PlaceVersion":123,"BaseUrl":"mete0r.xyz","MachineAddress":"localhost","JobId":"game1","PreferredPort":53640}}
|
||||
json.GameId = jobid
|
||||
json.Settings.PreferredPort = port
|
||||
json.Settings.MachineAddress = ip
|
||||
json.Settings.JobId = jobid
|
||||
json.Settings.PlaceId = parseFloat(placeid)
|
||||
json.Settings.UniverseId = json.Settings.PlaceId
|
||||
json.Settings.CreatorId = creatorid
|
||||
json.Settings.GameId = jobid
|
||||
|
||||
let xml = `<?xml version = "1.0" encoding = "UTF-8"?>
|
||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://roblox.com/RCCServiceSoap" xmlns:ns1="http://roblox.com/" xmlns:ns3="http://roblox.com/RCCServiceSoap12">
|
||||
<SOAP-ENV:Body>
|
||||
<ns1:OpenJob>
|
||||
<ns1:job>
|
||||
<ns1:id>${jobid}</ns1:id>
|
||||
<ns1:expirationInSeconds>60</ns1:expirationInSeconds>
|
||||
<ns1:category>2</ns1:category>
|
||||
<ns1:cores>1</ns1:cores>
|
||||
</ns1:job>
|
||||
<ns1:script>
|
||||
<ns1:name>game1</ns1:name>
|
||||
<ns1:script>${JSON.stringify(json)}</ns1:script>
|
||||
</ns1:script>
|
||||
</ns1:OpenJob>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>`
|
||||
|
||||
|
||||
//console.log(encodeURIComponent(JSON.stringify(json)))
|
||||
try {
|
||||
const result = await fetch(url+"/opengame/"+jobid+"/"+encodeURIComponent(JSON.stringify(json)))
|
||||
const data = await result.text()
|
||||
return resolve(
|
||||
data
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function OpenGame2020(jobid,port,ip,placeid,creatorid){
|
||||
return new Promise(async (resolve, reject) => {
|
||||
let json = {"Mode":"GameServer","GameId":"game1","Settings":{"IsRobloxPlace":false,"PlaceId":1,"CreatorId":1,"GameId":"00000000-0000-0000-0000-000000000132","GsmInterval":50,"MaxPlayers":100,"MaxGameInstances":52,"ApiKey":"egg","GameCode":"AAAAAAAAAAAAAA-a","PreferredPlayerCapacity":10,"DatacenterId":1,"PlaceVisitAccessKey":"rbx_evt_ftp","UniverseId":13058,"PlaceFetchUrl":"https://mete0r.xyz/asset?id=11","MatchmakingContextId":1,"CreatorType":"User","PlaceVersion":123,"BaseUrl":"mete0r.xyz","MachineAddress":"localhost","JobId":"game1","PreferredPort":53640}}
|
||||
json.GameId = jobid
|
||||
json.Settings.PreferredPort = port
|
||||
json.Settings.MachineAddress = ip
|
||||
json.Settings.JobId = jobid
|
||||
json.Settings.PlaceId = parseFloat(placeid)
|
||||
json.Settings.UniverseId = json.Settings.PlaceId
|
||||
json.Settings.CreatorId = creatorid
|
||||
json.Settings.GameId = jobid
|
||||
json.Settings.PlaceFetchUrl = "https://mete0r.xyz/asset?id="+parseFloat(placeid)
|
||||
|
||||
let xml = `<?xml version = "1.0" encoding = "UTF-8"?>
|
||||
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns2="http://roblox.com/RCCServiceSoap" xmlns:ns1="http://roblox.com/" xmlns:ns3="http://roblox.com/RCCServiceSoap12">
|
||||
<SOAP-ENV:Body>
|
||||
<ns1:OpenJob>
|
||||
<ns1:job>
|
||||
<ns1:id>${jobid}</ns1:id>
|
||||
<ns1:expirationInSeconds>60</ns1:expirationInSeconds>
|
||||
<ns1:category>2</ns1:category>
|
||||
<ns1:cores>1</ns1:cores>
|
||||
</ns1:job>
|
||||
<ns1:script>
|
||||
<ns1:name>game1</ns1:name>
|
||||
<ns1:script>${JSON.stringify(json)}</ns1:script>
|
||||
</ns1:script>
|
||||
</ns1:OpenJob>
|
||||
</SOAP-ENV:Body>
|
||||
</SOAP-ENV:Envelope>`
|
||||
|
||||
|
||||
//console.log(encodeURIComponent(JSON.stringify(json)))
|
||||
try {
|
||||
const result = await fetch(url+"/opengame2020/"+jobid+"/"+encodeURIComponent(JSON.stringify(json)))
|
||||
const data = await result.text()
|
||||
return resolve(
|
||||
data
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function CloseJob(jobid) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF - 8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
|
||||
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
|
||||
'xmlns:ns1': 'http://roblox.com/',
|
||||
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12'
|
||||
},
|
||||
'SOAP-ENV:Body': {
|
||||
'ns1:CloseJob': {
|
||||
'ns1:jobID': { _text: 'Test' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:CloseJob']['ns1:jobID']._text = jobid
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url+"/closejob/"+jobid)
|
||||
const data = await result.text()
|
||||
return resolve(
|
||||
data
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function OpenRender(userid,closeup) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const result = await fetch(url+"/openrender/"+userid+"/"+closeup)
|
||||
const data = await result.text()
|
||||
//console.log(data)
|
||||
if (data === '{"status": "error","error":"Already started"}'){
|
||||
return resolve(
|
||||
JSON.parse(data)
|
||||
)
|
||||
}
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function OpenRenderAsset(assetid,type) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const result = await fetch(url+"/openrenderasset/"+assetid+"/"+type)
|
||||
const data = await result.text()
|
||||
//console.log(data)
|
||||
if (data === '{"status": "error","error":"Already started"}'){
|
||||
return resolve(
|
||||
JSON.parse(data)
|
||||
)
|
||||
}
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function lol2(){
|
||||
const lol = await OpenRender(0)
|
||||
console.log(lol['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:OpenJobResponse']['ns1:OpenJobResult'][0]['ns1:value']._text)
|
||||
}
|
||||
|
||||
async function RenewLease(jobid,expiration) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
var xml = {
|
||||
_declaration: { _attributes: { version: '1.0', encoding: 'UTF-8' } },
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:ns1': 'http://roblox.com/',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance'
|
||||
},
|
||||
'SOAP-ENV:Body': {
|
||||
'ns1:RenewLease': {
|
||||
'ns1:jobID': { _text: 'Test' },
|
||||
'ns1:expirationInSeconds': { _text: '100' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:RenewLease']['ns1:jobID']._text = jobid
|
||||
xml['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:RenewLease']['ns1:expirationInSeconds']._text = expiration
|
||||
const body = convert.js2xml(xml, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url+"/renewlease/"+jobid+"/"+expiration)
|
||||
const data = await result.text()
|
||||
return resolve(
|
||||
data
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function Execute(jobid,json) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
const result = await fetch(url+"/executejson/"+jobid+"/"+encodeURIComponent(JSON.stringify(json)))
|
||||
const data = await result.text()
|
||||
return resolve(
|
||||
data
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function GetAllJobs() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const xmlData = (xml = {
|
||||
_declaration: {
|
||||
_attributes: { version: '1.0', encoding: 'UTF - 8' },
|
||||
},
|
||||
'SOAP-ENV:Envelope': {
|
||||
_attributes: {
|
||||
'xmlns:SOAP-ENV': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'xmlns:SOAP-ENC': 'http://schemas.xmlsoap.org/soap/encoding/',
|
||||
'xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||
'xmlns:xsd': 'http://www.w3.org/2001/XMLSchema',
|
||||
'xmlns:ns2': 'http://roblox.com/RCCServiceSoap',
|
||||
'xmlns:ns1': 'http://roblox.com/',
|
||||
'xmlns:ns3': 'http://roblox.com/RCCServiceSoap12',
|
||||
},
|
||||
'SOAP-ENV:Body': { 'ns1:GetAllJobsEx': {} },
|
||||
},
|
||||
})
|
||||
|
||||
const body = convert.js2xml(xmlData, { compact: true, spaces: 4 })
|
||||
|
||||
try {
|
||||
const result = await fetch(url, { method: 'POST', body })
|
||||
const data = await result.text()
|
||||
const convertedData = convert.xml2js(data, { compact: true, spaces: 4 })
|
||||
return resolve(
|
||||
convertedData['SOAP-ENV:Envelope']['SOAP-ENV:Body']['ns1:GetAllJobsExResponse']['ns1:GetAllJobsExResult']
|
||||
)
|
||||
} catch (error) {
|
||||
return reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
//RenewLease('game2',"69530318916789546987353800")
|
||||
async function lol(){
|
||||
let res = await GetAllJobs()
|
||||
//console.dir(res,{ depth: null })
|
||||
let exists = false
|
||||
if (res != "{}"){
|
||||
if (Array.isArray(res['ns1:Job']) === false){
|
||||
console.log('asd')
|
||||
//console.log(res['ns1:Job']['ns1:id']._text)
|
||||
if (res['ns1:Job']['ns1:id']._text === 'game2'){
|
||||
exists = true
|
||||
}
|
||||
}else{
|
||||
res['ns1:Job'].forEach(element => {
|
||||
if (element['ns1:id']?._text === 'game2'){
|
||||
exists = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
console.log(exists)
|
||||
}
|
||||
//lol()
|
||||
//GetAllJobs()
|
||||
//OpenGame('game2','3333','127.0.0.1','2')
|
||||
module.exports = {OpenGame,CloseJob,RenewLease,GetAllJobs,OpenRender,OpenRenderAsset,OpenGame2020,Execute}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
const express = require("express")
|
||||
const router = express.Router()
|
||||
const { requireAuth } = require('../../middleware/authmiddlewaregame')
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs')
|
||||
const key = fs.readFileSync('DefaultPrivateKey.pem')
|
||||
const { getPort, checkPort, getRandomPort, waitForPort } = require('get-port-please')
|
||||
const RCC_HOST = process.env.RCC_HOST
|
||||
var sanitize = require('mongo-sanitize');
|
||||
const games = require('./../../model/games.js')
|
||||
const signatures = require("./../signatures.js")
|
||||
const rcc = require('../../model/rcc2018.js')
|
||||
const rcctalk = require('../../rcctalk2018')
|
||||
const User = require('../../model/user.js')
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
const _2018placelauncher = async(req,res,next) => {
|
||||
var enabled = req.config
|
||||
if (enabled.GamesEnabled === false){
|
||||
return res.json({status:"error",error:"Games are disabled bad boy"})
|
||||
}
|
||||
var joinJson = {"ClientPort":0,"MachineAddress":"localhost","ServerPort":25564,"PingUrl":"","PingInterval":120,"UserName":"default","SeleniumTestMode":false,"UserId":0,"SuperSafeChat":false,"CharacterAppearance":"http://shitncumblox.gq/game/charapp?name=default","ClientTicket":"","GameId":1,"PlaceId":1818,"MeasurementUrl":"","WaitingForCharacterGuid":"cad99b30-7983-434b-b24c-eac12595e5fd","BaseUrl":"http://www.mete0r.xyz/","ChatStyle":"ClassicAndBubble","VendorId":0,"ScreenShotInfo":"","VideoInfo":"<?xml version=\"1.0\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mrss/\" xmlns:yt=\"http://gdata.youtube.com/schemas/2007\"><media:group><media:title type=\"plain\"><![CDATA[ROBLOX Place]]></media:title><media:description type=\"plain\"><![CDATA[ For more games visit http://www.roblox.com]]></media:description><media:category scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">Games</media:category><media:keywords>ROBLOX, video, free game, online virtual world</media:keywords></media:group></entry>","CreatorId":0,"CreatorTypeEnum":"User","MembershipType":"None","AccountAge":365,"CookieStoreFirstTimePlayKey":"rbx_evt_ftp","CookieStoreFiveMinutePlayKey":"rbx_evt_fmp","CookieStoreEnabled":true,"IsRobloxPlace":false,"GenerateTeleportJoin":false,"IsUnknownOrUnder13":false,"SessionId":"c25fd620-bbaa-4fb2-b022-3f053cdd1abd|00000000-0000-0000-0000-000000000000|0|204.236.226.210|8|2016-08-17T01:05:05.7115837Z|0|null|null|null|null","DataCenterId":0,"UniverseId":0,"BrowserTrackerId":0,"UsePortraitMode":false,"FollowUserId":0,"CharacterAppearanceId":1}
|
||||
if (!req.query.name && !req.query.placeId && !req.query.placeid){
|
||||
return res.json({status:"error",error:"no placeid bad"})
|
||||
}
|
||||
if (req.userdocument.gamejoin2018){
|
||||
return res.json({"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2018&auth="+req.query.auth??req.cookies.jwt,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""})
|
||||
}
|
||||
var sanitizedplaceid = sanitize(req.query.name??req.query.placeId??req.query.placeid)
|
||||
const game = await games.findOne({idofgame: sanitizedplaceid}).lean()
|
||||
if (!game){
|
||||
return res.json({status:"error",error:"that game doesn't exist!"})
|
||||
}
|
||||
if (game.version != "2018"){
|
||||
return next()
|
||||
}
|
||||
let instance = await rcc.findOne({PlaceId: sanitizedplaceid}).lean()
|
||||
if (instance && instance.Status === 2){
|
||||
|
||||
|
||||
// if an rcc instance already exists we don't need to create a new one so we will just drag them into the existing game
|
||||
joinJson.UserName = req.userdocument.username
|
||||
joinJson.UserId = req.userdocument.userid
|
||||
joinJson.CharacterAppearance = "http://mete0r.xyz/v1.1/avatar-fetch?userId" + req.userdocument.userid
|
||||
joinJson.MachineAddress = RCC_HOST // need to put rcc host here lol
|
||||
joinJson.ServerPort = instance.Port
|
||||
joinJson.PlaceId = instance.PlaceId
|
||||
joinJson.GameId = sanitizedplaceid
|
||||
joinJson.CharacterAppearanceId = req.userdocument.userid
|
||||
joinJson.MembershipType = req.userdocument.membership
|
||||
joinJson.CreatorId = game.useridofowner
|
||||
joinJson.SessionId = req.query.auth??req.cookies.jwt
|
||||
|
||||
const timestamp = Date.now()
|
||||
joinJson.ClientTicket = timestamp+";" // timestamp
|
||||
//create signature 1
|
||||
const sign1 = crypto.createSign('SHA1');
|
||||
sign1.update(`${req.userdocument.userid}\n`/*userid*/+`${req.userdocument.username}\n`/*username*/+`http://mete0r.xyz/v1.1/avatar-fetch?userId=${req.userdocument.userid}\n`/*charapp*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
|
||||
var signature1 = sign1.sign(key, "base64")
|
||||
joinJson.ClientTicket += signature1 + ";"
|
||||
|
||||
//create signature 2
|
||||
const sign2 = crypto.createSign('SHA1');
|
||||
sign2.update(`${req.userdocument.userid}\n`/*userid*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
|
||||
var signature2 = sign2.sign(key, "base64")
|
||||
joinJson.ClientTicket += signature2
|
||||
|
||||
req.userdocument.gamejoin2018 = JSON.stringify(joinJson)
|
||||
req.userdocument.markModified('gamejoin2018')
|
||||
await req.userdocument.save()
|
||||
var joinScriptJson = {"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2018&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
|
||||
|
||||
|
||||
return res.send(JSON.stringify(joinScriptJson))
|
||||
}
|
||||
if (instance && instance.Status === 1){
|
||||
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2018&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
|
||||
return res.send(JSON.stringify(joinScriptJson))
|
||||
}
|
||||
|
||||
|
||||
var port = await getPort({random: true})
|
||||
// launch job
|
||||
rcctalk.OpenGame("game"+sanitizedplaceid,port,RCC_HOST,sanitizedplaceid,game.useridofowner)
|
||||
//console.dir(response,{ depth: null })
|
||||
//console.dir(response,{ depth: null })
|
||||
|
||||
await rcc.create({
|
||||
PlaceId: sanitizedplaceid,
|
||||
Port: port,
|
||||
Status: 1 // 1 means loading
|
||||
})
|
||||
|
||||
//console.log(newrenderscript)
|
||||
|
||||
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
|
||||
return res.send(JSON.stringify(joinScriptJson))
|
||||
|
||||
}
|
||||
|
||||
router.all("/2018/join",requireAuth,_2018placelauncher,async (req, res) => {
|
||||
return res.json({status:"error",error:"Version different than client requested."})
|
||||
})
|
||||
|
||||
//rcctalk.CloseJob('game2')
|
||||
module.exports = {router: router, _2018placelauncher:_2018placelauncher}
|
||||
|
|
@ -0,0 +1,207 @@
|
|||
const express = require("express")
|
||||
const router = express.Router()
|
||||
const { requireAuth } = require('../../middleware/authmiddlewaregame')
|
||||
const crypto = require('crypto');
|
||||
const fs = require('fs')
|
||||
const key = fs.readFileSync('PrivateKey2020.txt')
|
||||
const { getPort, checkPort, getRandomPort, waitForPort } = require('get-port-please')
|
||||
const RCC_HOST = process.env.RCC_HOST
|
||||
var sanitize = require('mongo-sanitize');
|
||||
const games = require('./../../model/games.js')
|
||||
const signatures = require("./../signatures.js")
|
||||
const rcc = require('../../model/rcc2020.js')
|
||||
const rcctalk = require('../../rcctalk2018')
|
||||
const User = require('../../model/user.js')
|
||||
const bodyParser = require('body-parser')
|
||||
router.use(bodyParser.json())
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
const _2020placelauncher = async(req,res,next) => {
|
||||
var enabled = req.config
|
||||
if (enabled.GamesEnabled === false){
|
||||
return res.json({status:"error",error:"Games are disabled bad boy"})
|
||||
}
|
||||
if (req.headers?.['user-agent']?.includes("Android") === true || req.headers?.['user-agent']?.includes("iPhone") === true){
|
||||
console.log(req.headers)
|
||||
console.log(req.userdocument.username)
|
||||
}
|
||||
|
||||
if (req.method === "POST"){ // mobile join-game
|
||||
req.query.name = req.body.placeId
|
||||
}
|
||||
var joinJson = {"ClientPort":0,"MachineAddress":"localhost","ServerPort":25564,"PingUrl":"","PingInterval":120,"UserName":"default","SeleniumTestMode":false,"UserId":0,"SuperSafeChat":false,"CharacterAppearance":"http://shitncumblox.gq/game/charapp?name=default","ClientTicket":"","GameId":1,"PlaceId":1818,"MeasurementUrl":"","WaitingForCharacterGuid":"cad99b30-7983-434b-b24c-eac12595e5fd","BaseUrl":"http://www.mete0r.xyz/","ChatStyle":"ClassicAndBubble","VendorId":0,"ScreenShotInfo":"","VideoInfo":"<?xml version=\"1.0\"?><entry xmlns=\"http://www.w3.org/2005/Atom\" xmlns:media=\"http://search.yahoo.com/mrss/\" xmlns:yt=\"http://gdata.youtube.com/schemas/2007\"><media:group><media:title type=\"plain\"><![CDATA[ROBLOX Place]]></media:title><media:description type=\"plain\"><![CDATA[ For more games visit http://www.roblox.com]]></media:description><media:category scheme=\"http://gdata.youtube.com/schemas/2007/categories.cat\">Games</media:category><media:keywords>ROBLOX, video, free game, online virtual world</media:keywords></media:group></entry>","CreatorId":0,"CreatorTypeEnum":"User","MembershipType":"None","AccountAge":365,"CookieStoreFirstTimePlayKey":"rbx_evt_ftp","CookieStoreFiveMinutePlayKey":"rbx_evt_fmp","CookieStoreEnabled":true,"IsRobloxPlace":false,"GenerateTeleportJoin":false,"IsUnknownOrUnder13":false,"SessionId":"c25fd620-bbaa-4fb2-b022-3f053cdd1abd|00000000-0000-0000-0000-000000000000|0|204.236.226.210|8|2016-08-17T01:05:05.7115837Z|0|null|null|null|null","DataCenterId":0,"UniverseId":0,"BrowserTrackerId":0,"UsePortraitMode":false,"FollowUserId":0,"CharacterAppearanceId":1}
|
||||
if (!req.query.name && !req.query.placeId && !req.query.placeid){
|
||||
return res.json({status:"error",error:"no placeid bad"})
|
||||
}
|
||||
if (req.userdocument.gamejoin2020){
|
||||
return res.json({"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+req.query.auth??req.cookies.jwt,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""})
|
||||
}
|
||||
var sanitizedplaceid = sanitize(req.query.name??req.query.placeId??req.query.placeid)
|
||||
const game = await games.findOne({idofgame: sanitizedplaceid}).lean()
|
||||
if (!game){
|
||||
return res.json({status:"error",error:"that game doesn't exist!"})
|
||||
}
|
||||
if (game.version != "2020"){
|
||||
return next()
|
||||
}
|
||||
let instance = await rcc.findOne({PlaceId: sanitizedplaceid}).lean()
|
||||
if (instance && instance.Status === 2){
|
||||
|
||||
|
||||
// if an rcc instance already exists we don't need to create a new one so we will just drag them into the existing game
|
||||
joinJson.UserName = req.userdocument.username
|
||||
joinJson.UserId = req.userdocument.userid
|
||||
joinJson.CharacterAppearance = "http://mete0r.xyz/v1.1/avatar-fetch?userId=" + req.userdocument.userid
|
||||
joinJson.MachineAddress = RCC_HOST // need to put rcc host here lol
|
||||
joinJson.ServerPort = instance.Port
|
||||
joinJson.PlaceId = instance.PlaceId
|
||||
joinJson.GameId = sanitizedplaceid
|
||||
joinJson.CharacterAppearanceId = req.userdocument.userid
|
||||
joinJson.MembershipType = req.userdocument.membership
|
||||
joinJson.CreatorId = game.useridofowner
|
||||
joinJson.SessionId = req.query.auth??req.cookies.jwt
|
||||
|
||||
const timestamp = Date.now()
|
||||
joinJson.ClientTicket = timestamp+";" // timestamp
|
||||
//create signature 1
|
||||
const sign1 = crypto.createSign('SHA1');
|
||||
sign1.update(`${req.userdocument.userid}\n`/*userid*/+`${req.userdocument.username}\n`/*username*/+`${"0"}\n`/*userid 2 that 0k wants for some reason what a retard*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
|
||||
var signature1 = sign1.sign(key, "base64")
|
||||
joinJson.ClientTicket += signature1 + ";"
|
||||
//create signature 2
|
||||
const sign2 = crypto.createSign('SHA1');
|
||||
sign2.update(`${req.userdocument.userid}\n`/*userid*/+`game${sanitizedplaceid}\n`/*jobid*/+ timestamp/*timestamp*/)
|
||||
var signature2 = sign2.sign(key, "base64")
|
||||
joinJson.ClientTicket += signature2 + ";4"
|
||||
|
||||
if (req.method === "POST" && req.body.isTeleport){ // mobile join-game
|
||||
const mobileJoin =
|
||||
{
|
||||
"ClientPort": 0,
|
||||
"MachineAddress": RCC_HOST,
|
||||
"ServerPort": instance.Port,
|
||||
"ServerConnections": [
|
||||
{
|
||||
"Address": RCC_HOST,
|
||||
"Port": instance.Port
|
||||
}
|
||||
],
|
||||
"DirectServerReturn": true,
|
||||
"TokenGenAlgorithm": 0,
|
||||
"PepperId": 0,
|
||||
"TokenValue": "vg",
|
||||
"PingUrl": "",
|
||||
"PingInterval": 0,
|
||||
"UserName": req.userdocument.username,
|
||||
"SeleniumTestMode": false,
|
||||
"UserId": req.userdocument.userid,
|
||||
"RobloxLocale": "",
|
||||
"GameLocale": "",
|
||||
"SuperSafeChat": false,
|
||||
"CharacterAppearance": "http://mete0r.xyz/v1.1/avatar-fetch?userId=" + req.userdocument.userid,
|
||||
"ClientTicket": joinJson.ClientTicket,
|
||||
"GameId": ""+sanitizedplaceid,
|
||||
"PlaceId": sanitizedplaceid,
|
||||
"BaseUrl": "http://www.mete0r.xyz/",
|
||||
"ChatStyle": "ClassicAndBubble",
|
||||
"CreatorId": game.useridofowner,
|
||||
"CreatorTypeEnum": "User",
|
||||
"MembershipType": req.userdocument.membership,
|
||||
"AccountAge": 365,
|
||||
"CookieStoreFirstTimePlayKey": "rbx_evt_ftp",
|
||||
"CookieStoreFiveMinutePlayKey": "rbx_evt_fmp",
|
||||
"CookieStoreEnabled": false,
|
||||
"IsUnknownOrUnder13": false,
|
||||
"GameChatType": "AllUsers",
|
||||
"SessionId": req.query.auth??req.cookies.jwt,
|
||||
"AnalyticsSessionId": "",
|
||||
"DataCenterId": 0,
|
||||
"UniverseId": sanitizedplaceid,
|
||||
"FollowUserId": 0,
|
||||
"characterAppearanceId": req.userdocument.userid,
|
||||
"CountryCode": "US",
|
||||
"AlternateName": "",
|
||||
"RandomSeed1": "57575745353",
|
||||
"ClientPublicKeyData": ""
|
||||
}
|
||||
|
||||
console.log(mobileJoin)
|
||||
return res.json({
|
||||
"jobId": "Test",
|
||||
"status": 2,
|
||||
"joinScriptUrl": `http://mete0r.xyz/game/join.ashx?ver=2020&auth=${req.query.auth??req.cookies.jwt}`,
|
||||
"authenticationUrl": "http://mete0r.xyz/Login/Negotiate.ashx",
|
||||
"authenticationTicket": "SomeTicketThatDosentCrash",
|
||||
"message": "",
|
||||
"joinScript": mobileJoin
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
req.userdocument.gamejoin2020 = JSON.stringify(joinJson)
|
||||
req.userdocument.markModified('gamejoin2020')
|
||||
await req.userdocument.save()
|
||||
var joinScriptJson = {"jobId":"Test","status":2,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
|
||||
|
||||
|
||||
return res.send(JSON.stringify(joinScriptJson))
|
||||
}
|
||||
|
||||
if (instance && instance.Status === 1){
|
||||
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
|
||||
|
||||
if (req.method === "POST" && req.body.isTeleport){ // mobile join-game
|
||||
return res.json({
|
||||
"jobId": "Test",
|
||||
"status": 0,
|
||||
"joinScriptUrl": "http://mete0r.xyz/game/join.ashx?ver=2020&auth="+req.query.auth??req.cookies.jwt,
|
||||
"authenticationUrl": "http://mete0r.xyz/Login/Negotiate.ashx",
|
||||
"authenticationTicket": "SomeTicketThatDosentCrash",
|
||||
"message": ""
|
||||
})
|
||||
|
||||
}
|
||||
return res.send(JSON.stringify(joinScriptJson))
|
||||
}
|
||||
|
||||
var port = 53640 + Math.floor(Math.random() * 100)
|
||||
// launch job
|
||||
rcctalk.OpenGame2020("game"+sanitizedplaceid,port,RCC_HOST,sanitizedplaceid,game.useridofowner)
|
||||
//console.dir(response,{ depth: null })
|
||||
|
||||
await rcc.create({
|
||||
PlaceId: sanitizedplaceid,
|
||||
Port: port,
|
||||
Status: 1 // 1 means loading
|
||||
})
|
||||
|
||||
//console.log(newrenderscript)
|
||||
|
||||
var joinScriptJson = {"jobId":"Test","status":1,"joinScriptUrl":"http://mete0r.xyz/game/join.ashx?ver=2020&auth="+joinJson.SessionId,"authenticationUrl":"http://mete0r.xyz/Login/Negotiate.ashx","authenticationTicket":"SomeTicketThatDosentCrash","message":""}
|
||||
|
||||
if (req.method === "POST" && req.body.isTeleport){ // mobile join-game
|
||||
return res.json({
|
||||
"jobId": "Test",
|
||||
"status": 0,
|
||||
"joinScriptUrl": "http://mete0r.xyz/game/join.ashx?ver=2020&auth="+req.query.auth??req.cookies.jwt,
|
||||
"authenticationUrl": "http://mete0r.xyz/Login/Negotiate.ashx",
|
||||
"authenticationTicket": "SomeTicketThatDosentCrash",
|
||||
"message": ""
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
return res.send(JSON.stringify(joinScriptJson))
|
||||
}
|
||||
|
||||
router.all(["/MTwentyTwenty.ashx","/2020/join","/join-game"],requireAuth,_2020placelauncher,async (req, res) => {
|
||||
return res.json({status:"error",error:"Version different than client requested."})
|
||||
})
|
||||
|
||||
//rcctalk.CloseJob('game2')
|
||||
module.exports = {router: router, _2020placelauncher:_2020placelauncher}
|
||||