Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- -- @CloneTrooper1019, 2014
- -- (WARNING: THIS IS IN BETA)
- --
- -- This script pulls a 3D Thumbnail from a roblox profile, and converts it into a StudioMDL file (.smd), which can be compiled into a Source Engine Game! It rigs the model too :)
- -- Steps to use:
- --
- -- 1: Go to your Roblox Studio Settings, and make sure your "Maximum Output Lines" is set to around 99999 or higher
- -- 2: Make sure your output window is visible.
- -- 3: Start a Roblox Server
- -- 4: If the hint tells you to enable the HttpService, go into the Explorer, select the HttpService and make sure that HttpEnabled is checked
- -- 5: When the hint above says "WRITING STUDIOMDL DATA", quickly right click the output and press "Clear Output"
- -- 6: Wait for it to finish processing.
- --
- -- The output will now display a full .smd file of the character you inputted.
- -- Most of you probably won't know what to do with it, and thats fine. This script is for advanced users :P
- -- You can look at these pages if you'd like to proceed further.
- --
- -- https://developer.valvesoftware.com/wiki/Crowbar
- -- https://developer.valvesoftware.com/wiki/QC
- --
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- USER_ID = 2032622
- ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- h = game:GetService("HttpService")
- bones = {
- Torso1 =
- {
- Name = "Torso";
- Offset = Vector3.new();
- Link = 0;
- },
- LeftArm1 =
- {
- Name = "Left Shoulder";
- Offset = Vector3.new(1,0.5,0);
- Link = 1;
- },
- RightArm1 =
- {
- Name = "Right Shoulder";
- Offset = Vector3.new(-1,0.5,0);
- Link = 2;
- },
- LeftLeg1 =
- {
- Name = "Left Hip";
- Offset = Vector3.new(1,-1,0);
- Link = 3;
- },
- RightLeg1 =
- {
- Name = "Right Hip";
- Offset = Vector3.new(-1,-1,0);
- Link = 4;
- },
- Head1 =
- {
- Name = "Neck";
- Offset = Vector3.new(0,1,0);
- Link = 5;
- }
- }
- tempFile =
- [[version 1
- nodes
- 0 "Torso" -1
- 1 "Left Shoulder" 0
- 2 "Right Shoulder" 0
- 3 "Left Hip" 0
- 4 "Right Hip" 0
- 5 "Neck" 0
- end
- skeleton
- time 0]]
- function canGetAsync()
- local can = pcall(function ()
- return h:GetAsync("http://www.google.com")
- end)
- return can
- end
- if not canGetAsync() then
- local yieldHint = Instance.new("Hint",workspace)
- while not game:findFirstChild("NetworkServer") do
- yieldHint.Text = "["..script:GetFullName().."] Can't run compiler until a server is running. Read the script for more information."
- wait()
- end
- while not canGetAsync() do
- yieldHint.Text = "["..script:GetFullName().."] Please make sure that HttpService.HttpEnabled is checked!"
- wait()
- end
- yieldHint:Destroy()
- end
- function ridiculousJSONAsync(url,tag,decodeAgain)
- local t = h:JSONDecode(h:GetAsync(url))
- local async = h:GetAsync(t[tag])
- return (decodeAgain and h:JSONDecode(async) or async)
- end
- function parseOBJ(objFile,scale,origin)
- -- Parses an OBJ File into a data array.
- local scale = scale or 1
- local origin = origin or Vector3.new()
- local obj = {
- Verts = {};
- Norms = {};
- Texs = {};
- Faces = {};
- }
- local currentMtl = "";
- local currentGroup = "root";
- for line in objFile:gmatch("[^\r\n]+") do
- if #line > 0 then
- local info = {}
- local tag = ""
- local process = ""
- local readChars = 0
- for char in line:gmatch(".") do
- readChars = readChars + 1
- if char == " " then
- if tag == "" then
- tag = process
- else
- table.insert(info,tonumber(process) or process)
- end
- process = ""
- else
- process = process .. char
- if readChars == #line then
- table.insert(info,tonumber(process) or process)
- end
- end
- end
- if tag == "usemtl" then
- currentMtl = info[1]
- elseif tag == "g" then
- local group = info[1]
- currentGroup = info[1]
- elseif tag == "v" then
- local vec = Vector3.new(unpack(info))
- vec = (vec - origin) * scale
- table.insert(obj.Verts,{vec.X,vec.Y,vec.Z})
- elseif tag == "vn" then
- local vec = Vector3.new(unpack(info))*scale
- table.insert(obj.Norms,{vec.X,vec.Y,vec.Z})
- elseif tag == "vt" then
- table.insert(obj.Texs,info)
- elseif tag == "f" then
- local face = {
- Material = currentMtl;
- Group = currentGroup;
- Coords = {};
- }
- for _,pair in pairs(info) do
- local triangle = {}
- local v,t,n
- if type(pair) == "number" then
- v = tonumber(pair)
- elseif string.find(pair,"//") then
- v,n = string.match(pair,"(%S+)//(%S+)")
- else
- v,t,n = string.match(pair,"(%S+)/(%S+)/(%S+)")
- if not v or not t or not n then
- v,t = string.match(pair,"(%S+)/(%S+)")
- end
- end
- triangle.Vert = tonumber(v)
- triangle.Tex = tonumber(t)
- triangle.Norm = tonumber(n)
- table.insert(face.Coords,triangle)
- end
- table.insert(obj.Faces,face)
- end
- end
- end
- return obj
- end
- function parseMTL(mtlFile)
- -- Parses an OBJ File into a data array.
- local mtl = {}
- local currentMtl = ""
- local dump
- for line in mtlFile:gmatch("[^\r\n]+") do
- if #line > 0 then
- local info = {}
- local tag = ""
- local process = ""
- local readChars = 0
- for char in line:gmatch(".") do
- readChars = readChars + 1
- if char == " " then
- if tag == "" then
- tag = process
- else
- table.insert(info,tonumber(process) or process)
- end
- process = ""
- else
- process = process .. char
- if readChars == #line then
- table.insert(info,tonumber(process) or process)
- end
- end
- end
- if tag == "newmtl" then
- if dump then
- table.insert(mtl,dump);
- end
- dump = {};
- dump.Material = info[1];
- elseif tag == "map_d" then
- dump.HashTex = info[1];
- end
- end
- end
- return mtl;
- end
- function NewFileWriter(initial)
- local file = initial or ""
- local writer = {}
- function writer:Add(...)
- for _,line in pairs{...} do
- if file == "" then
- file = file .. line
- else
- file = file .. "\n" .. line
- end
- end
- end
- function writer:Dump()
- return file
- end
- return writer
- end
- function float(num)
- -- Obj Files have some insanely low numbers sometimes.
- -- I need to cap them to around 7 decimal places.
- if math.floor(num) == num then
- return tostring(num)
- else
- local omg = 10^99
- local fix = math.floor(num*omg)/omg
- local fl = tostring(math.floor(fix))
- local str = tostring(fix)
- while (#str - #fl) < 7 do
- str = str .. "0"
- end
- return str
- end
- end
- function unwrap(this)
- local str = ""
- for _,v in pairs(this) do
- if str ~= "" then
- str = str .. " "
- end
- str = str .. float(v)
- end
- return str
- end
- function calculateOrigin(obj,group)
- local x,y,z = {},{},{}
- local function avg(dump)
- local a = 0
- for _,v in pairs(dump) do
- a = a + v
- end
- local total = #dump/2
- a = a / #dump
- return a
- end
- for _,face in pairs(obj.Faces) do
- if face.Group == group then
- for _,coord in pairs(face.Coords) do
- local vert = obj.Verts[coord.Vert]
- table.insert(x,vert[1])
- table.insert(y,vert[2])
- table.insert(z,vert[3])
- end
- end
- end
- return Vector3.new(avg(x),avg(y),avg(z))
- end
- function dumpVector3(v3)
- return float(v3.X).." "..float(v3.Y).." "..float(v3.Z)
- end
- function WriteCharacterSMD(userId)
- local data = ridiculousJSONAsync("http://rproxy.tk/avatar-thumbnail-3d/json?userId=" .. userId,"Url",true)
- local objFile = ridiculousJSONAsync("http://rproxy.tk/thumbnail/resolve-hash/" .. data.obj,"Url")
- local a = data.aabb.min;
- local b = data.aabb.max;
- local scale = 10
- local origin do
- a = Vector3.new(a.x,a.y,a.z)
- b = Vector3.new(b.x,b.y,b.z)
- origin = a:lerp(b,.5)
- end
- local obj = parseOBJ(objFile,scale,origin)
- local file = NewFileWriter(tempFile)
- local ignoreMtl do
- local avatar = h:GetAsync("http://rproxy.tk/Asset/AvatarAccoutrements.ashx?userId=2032622")
- local gearId = string.match(avatar,"?id=(%d+)&equipped=1")
- if gearId then
- local gearData = ridiculousJSONAsync("http://rproxy.tk/asset-thumbnail-3d/json?assetId=" .. gearId,"Url",true)
- local hashTex = gearData.textures[1]
- if hashTex then
- local mtlFile = ridiculousJSONAsync("http://rproxy.tk/thumbnail/resolve-hash/" .. data.mtl,"Url")
- local mtl = parseMTL(mtlFile)
- for _,v in pairs(mtl) do
- if v.HashTex == hashTex then
- ignoreMtl = v.Material
- break
- end
- end
- end
- end
- end
- local groups = {}
- for _,face in pairs(obj.Faces) do
- if not groups[face.Group] then
- groups[face.Group] = true;
- end
- end
- local isPlayerType = (groups["Player11"] ~= nil)
- local fix = {}
- for k in pairs(groups) do
- table.insert(fix,k)
- end
- groups = fix
- local function getLink(group)
- if bones[group] then
- return bones[group].Link
- elseif string.find(group,"Player1") then
- local num = tonumber(string.match(group,"Player1(%d+)"))
- local ref = { [0] = "Head1",[1] = "Torso1",[2] = "LeftArm1",[3] = "RightArm1",[4] = "LeftLeg1",[5] = "RightLeg1" }
- if num then
- local key = ref[#groups-num]
- if key then
- return bones[key].Link
- else
- return 5
- end
- end
- else
- return 5
- end
- end
- local function getRealName(name)
- if not isPlayerType then
- return name
- else
- local refs = {Head1 = 0, Torso1 = 1, LeftArm1 = 2, RightArm1 = 3, LeftLeg1 = 4, RightLeg1 = 5}
- local ref = refs[name]
- if ref then
- return "Player1" .. #groups - refs[name]
- else
- return name
- end
- end
- end
- local lines = {}
- for name,data in pairs(bones) do
- name = getRealName(name)
- local o = (data.Offset * scale)
- if name == "Torso1" or name == getRealName("Torso1") then
- o = o + calculateOrigin(obj,name)
- end
- local bone = data.Link .." " .. dumpVector3(o) .. "0 0 0"
- table.insert(lines,bone)
- end
- file:Add("end","triangles")
- local h = Instance.new("Hint",workspace)
- h.Archivable = false
- for count,face in pairs(obj.Faces) do
- if count % 50 == 0 then
- h.Text = "PROCESSING STUDIOMDL DATA ("..count.."/"..#obj.Faces..")"
- wait()
- end
- if face.Material ~= ignoreMtl and face.Group ~= "Humanoidrootpart1" then
- file:Add(face.Material)
- local link = getLink(face.Group)
- for _,coord in pairs(face.Coords) do
- local vert = obj.Verts[coord.Vert]
- local norm = obj.Norms[coord.Norm]
- local tex = obj.Texs[coord.Tex]
- file:Add(link .. " " .. unwrap(vert) .. " " .. unwrap(norm) .. " " .. unwrap(tex))
- end
- end
- end
- h.Text = "DONE. CHECK THE OUTPUT"
- game:GetService("Debris"):AddItem(h,1)
- file:Add("end")
- print(file:Dump())
- end
- WriteCharacterSMD(USER_ID)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement