Beispiel #1
0
        public Dictionary <string, AnimationId> CollectAnimationIds(UserAvatar avatar)
        {
            Contract.Requires(avatar != null);

            var userAnims = avatar.Assets
                            .Where(asset => AssetGroups.IsTypeInGroup(asset.Type, AssetGroup.Animations))
                            .ToDictionary(asset => Rbx2Source.GetEnumName(asset.Type).Replace("Animation", ""));

            var animIds = new Dictionary <string, AnimationId>();

            foreach (string animName in R15_ANIMATION_IDS.Keys)
            {
                AnimationId animId = new AnimationId();

                if (userAnims.ContainsKey(animName))
                {
                    animId.AnimationType = AnimationType.R15AnimFolder;
                    animId.AssetId       = userAnims[animName].Id;
                }
                else
                {
                    animId.AnimationType = AnimationType.KeyframeSequence;
                    animId.AssetId       = R15_ANIMATION_IDS[animName];
                }

                animIds.Add(animName, animId);
            }

            if (userAnims.ContainsKey("Idle"))
            {
                // Remove default lookaround
                if (animIds.ContainsKey("Idle2"))
                {
                    animIds.Remove("Idle2");
                }

                // If this isn't rthro idle...
                long animId = userAnims["Idle"].Id;

                if (animId != 2510235063)
                {
                    // Remove default pose
                    if (animIds.ContainsKey("Pose"))
                    {
                        animIds.Remove("Pose");
                    }

                    // Append the pose animation
                    AnimationId pose = new AnimationId()
                    {
                        AnimationType = AnimationType.R15AnimFolder,
                        AssetId       = animId
                    };

                    animIds.Add("Pose", pose);
                }
            }

            return(animIds);
        }
        public static BoneKeyframe AssembleBones(StudioMdlWriter meshBuilder, BasePart rootPart)
        {
            Rbx2Source.Print("Building Skeleton...");

            BoneKeyframe kf = new BoneKeyframe();

            List <Bone> bones = kf.Bones;
            List <Node> nodes = meshBuilder.Nodes;

            Bone rootBone = new Bone(rootPart.Name, rootPart);

            rootBone.C0           = new CFrame();
            rootBone.IsAvatarBone = true;
            bones.Add(rootBone);

            Node rootNode = rootBone.Node;

            rootNode.NodeIndex = 0;
            nodes.Add(rootNode);

            // Assemble the base rig.
            BoneAssemblePrep prep = new BoneAssemblePrep(ref bones, ref nodes);

            GenerateBones(prep, rootPart.GetChildrenOfClass <Attachment>());

            // Assemble the accessories.
            prep.AllowNonRigs = true;
            GenerateBones(prep, prep.NonRigs.ToArray());

            // Apply the rig cframe data.
            ApplyBoneCFrames(rootPart);
            meshBuilder.Skeleton.Add(kf);

            return(kf);
        }
Beispiel #3
0
        public static string PendCdn(string address, bool log = true)
        {
            string result = null;
            bool   final  = false;
            string dots   = "..";

            while (!final && dots.Length <= 13)
            {
                CdnPender pender = DownloadJSON <CdnPender>(address);
                final  = pender.Final;
                result = pender.Url;

                if (!final)
                {
                    dots += ".";

                    if (log)
                    {
                        Rbx2Source.Print("Waiting for finalization of " + address + dots);
                    }

                    wait(1f);
                }
            }

            if (dots.Length > 13)
            {
                throw new Exception("CdnPender timed out after 10 retries! Roblox's servers may be overloaded right now.\nTry again after a few minutes!");
            }

            return(result);
        }
        public static Folder AppendCharacterAssets(UserAvatar avatar, string avatarType, string context = "CHARACTER")
        {
            Rbx2Source.PrintHeader("GATHERING " + context + " ASSETS");

            Folder characterAssets = new Folder();

            AssetInfo[] assets = avatar.Assets;

            foreach (AssetInfo info in assets)
            {
                long  id    = info.Id;
                Asset asset = Asset.Get(id);

                Folder import       = RBXM.LoadFromAsset(asset);
                Folder typeSpecific = import.FindFirstChild <Folder>(avatarType);

                if (typeSpecific != null)
                {
                    import = typeSpecific;
                }

                import.ForEachChild((obj) => obj.Parent = characterAssets);
            }

            return(characterAssets);
        }
        public static Folder AppendCharacterAssets(UserAvatar avatar, string avatarType, string context = "CHARACTER")
        {
            Contract.Requires(avatar != null);
            Rbx2Source.PrintHeader("GATHERING " + context + " ASSETS");

            Folder characterAssets = new Folder();

            AssetInfo[] assets = avatar.Assets;

            foreach (AssetInfo info in assets)
            {
                long  id    = info.Id;
                Asset asset = Asset.Get(id);

                Instance import       = asset.OpenAsModel();
                Folder   typeSpecific = import.FindFirstChild <Folder>(avatarType);

                if (typeSpecific != null)
                {
                    import = typeSpecific;
                }

                var children = import
                               .GetChildren()
                               .ToList();

                children.ForEach((obj) => obj.Parent = characterAssets);
            }

            return(characterAssets);
        }
Beispiel #6
0
        public static void EmptyOutFiles(string folder, bool recursive = true)
        {
            DirectoryInfo info = new DirectoryInfo(folder);

            info.Attributes = FileAttributes.Normal;

            foreach (FileInfo file in info.GetFiles())
            {
                try
                {
                    file.Attributes = FileAttributes.Normal;
                    file.Delete();
                }
                catch
                {
                    Rbx2Source.Print("{0} is locked.", file.Name);
                }
            }

            if (recursive)
            {
                foreach (DirectoryInfo directory in info.GetDirectories())
                {
                    directory.Attributes = FileAttributes.Normal;
                    EmptyOutFiles(directory.FullName, true);
                }
            }
        }
        public static Folder AppendCharacterAssets(UserAvatar avatar, string avatarType)
        {
            Rbx2Source.PrintHeader("GATHERING CHARACTER ASSETS");

            Folder      characterAssets = new Folder();
            List <long> assetIds        = avatar.AccessoryVersionIds;

            foreach (long id in assetIds)
            {
                Asset  asset        = Asset.Get(id, "/asset/?assetversionid=");
                Folder import       = RBXM.LoadFromAsset(asset);
                Folder typeSpecific = import.FindFirstChild <Folder>(avatarType);
                if (typeSpecific != null)
                {
                    import = typeSpecific;
                }

                foreach (Instance obj in import.GetChildren())
                {
                    obj.Parent = characterAssets;
                }
            }

            return(characterAssets);
        }
        public Task Run()
        {
            List <string> paramStrings = new List <string>();

            foreach (UtilParameter parameter in parameters)
            {
                paramStrings.Add(parameter.ToString());
            }

            ProcessStartInfo info = new ProcessStartInfo();

            info.Arguments              = string.Join(" ", paramStrings.ToArray());
            info.FileName               = appPath;
            info.CreateNoWindow         = true;
            info.UseShellExecute        = false;
            info.RedirectStandardOutput = true;
            Process      process = Process.Start(info);
            StreamReader output  = process.StandardOutput;
            Task         runTask = Task.Run(() =>
            {
                while (true)
                {
                    Task <string> nextLineAsync = output.ReadLineAsync();
                    nextLineAsync.Wait(1000);
                    string nextLine = nextLineAsync.Result;
                    if (nextLine == null)
                    {
                        break;
                    }
                    Rbx2Source.Print(nextLine);
                }
            });

            return(runTask);
        }
Beispiel #9
0
        public void SetGuide(string guideName, Rectangle guideSize, AvatarType avatarType)
        {
            string avatarTypeName = Rbx2Source.GetEnumName(avatarType);
            string guidePath      = "AvatarData/" + avatarType + "/Compositing/" + guideName + ".mesh";
            Asset  guideAsset     = Asset.FromResource(guidePath);

            Guide = Mesh.FromAsset(guideAsset);
            Rect  = guideSize;
        }
Beispiel #10
0
        public void Write(StringWriter buffer, int stack = 0)
        {
            string tab = "";

            for (int i = 0; i < stack; i++)
            {
                tab += "\t";
            }

            List <string> lineBuff = new List <string>();

            lineBuff.Add(tab + "$" + Name.ToLower());
            foreach (string option in Options)
            {
                lineBuff.Add(option);
            }

            Rbx2Source.Print("Writing Command {0}", string.Join(" ", lineBuff.ToArray()));

            bool hasParameters = (Params.Count > 0);

            if (hasParameters)
            {
                lineBuff.Add(tab + "{");
            }

            string firstLine = string.Join(" ", lineBuff.ToArray());

            buffer.WriteLine(tab + firstLine);

            if (hasParameters)
            {
                foreach (QCParam param in Params)
                {
                    List <string> paramBuff = new List <string>();
                    paramBuff.Add(param.Name);
                    foreach (string value in param.Values)
                    {
                        paramBuff.Add(value);
                    }

                    string result = string.Join(" ", paramBuff);
                    buffer.WriteLine(tab + "\t" + result);
                }
                buffer.WriteLine("}\n");
            }
            else
            {
                foreach (QCommand subCommand in SubCommands)
                {
                    subCommand.Write(buffer, stack + 1);
                }
            }
        }
        public static void BuildAvatarGeometry(StudioMdlWriter meshBuilder, StudioBone bone)
        {
            Contract.Requires(meshBuilder != null && bone != null);

            string task = "BuildGeometry_" + bone.Node.Name;

            Rbx2Source.ScheduleTasks(task);

            Node     node = bone.Node;
            BasePart part = bone.Part1;

            bool   isAvatarLimb = bone.IsAvatarBone;
            string matName      = part.Name;

            if (isAvatarLimb)
            {
                BodyPart?limb = GetLimb(part);

                if (!limb.HasValue)
                {
                    throw new ArgumentException("Provided StudioBone did not point to a limb correctly.");
                }

                matName = Rbx2Source.GetEnumName(limb.Value);
            }

            var material = new ValveMaterial()
            {
                UseAvatarMap = isAvatarLimb
            };

            Rbx2Source.Print("Building Geometry for {0}", part.Name);
            Rbx2Source.IncrementStack();

            Mesh geometry = Mesh.BakePart(part, material);

            meshBuilder.Materials[matName] = material;

            for (int i = 0; i < geometry.NumFaces; i++)
            {
                Triangle tri = new Triangle()
                {
                    Node      = node,
                    FaceIndex = i,
                    Mesh      = geometry,
                    Material  = matName
                };

                meshBuilder.Triangles.Add(tri);
            }

            Rbx2Source.DecrementStack();
            Rbx2Source.MarkTaskCompleted(task);
        }
Beispiel #12
0
        private static void AddParts(List <BasePart> parts, Instance scan)
        {
            foreach (BasePart part in scan.GetChildrenOfClass <BasePart>())
            {
                if (part.Transparency < 1)
                {
                    parts.Add(part);
                    Rbx2Source.Print("Found Part {0}", part.Name);
                }
            }

            scan.ForEachChild(inst => AddParts(parts, inst));
        }
        public static void BuildAvatarGeometry(StudioMdlWriter meshBuilder, Bone bone)
        {
            string task = "BuildGeometry_" + bone.Node.Name;

            Rbx2Source.ScheduleTasks(task);
            Node node         = bone.Node;
            Part part         = bone.Part1;
            bool IsAvatarLimb = bone.IsAvatarBone;

            string materialName;

            if (IsAvatarLimb)
            {
                Limb limb = GetLimb(part);
                materialName = Rbx2Source.GetEnumName(limb);
            }
            else
            {
                materialName = part.Name;
            }

            Material material = new Material();

            material.UseAvatarMap = IsAvatarLimb;

            Rbx2Source.Print("Building Geometry for {0}", part.Name);
            Rbx2Source.IncrementStack();

            Mesh geometry = Mesh.BakePart(part, material);

            if (!meshBuilder.Materials.ContainsKey(materialName))
            {
                meshBuilder.Materials.Add(materialName, material);
            }

            for (int i = 0; i < geometry.FaceCount; i++)
            {
                Triangle tri = new Triangle();
                tri.Node      = node;
                tri.Mesh      = geometry;
                tri.FaceIndex = i;
                tri.Material  = materialName;

                meshBuilder.Triangles.Add(tri);
            }

            Rbx2Source.DecrementStack();
            Rbx2Source.MarkTaskCompleted(task);
        }
        private static void AddParts(List <Part> parts, Instance scan)
        {
            foreach (Part part in scan.GetChildrenOfClass <Part>())
            {
                if (part.Transparency < 1)
                {
                    parts.Add(part);
                    Rbx2Source.Print("Found Part {0}", part.Name);
                }
            }

            foreach (Instance inst in scan.GetChildren())
            {
                AddParts(parts, inst);
            }
        }
        public static void BuildAvatarGeometry(StudioMdlWriter meshBuilder, Bone bone)
        {
            string task = "BuildGeometry_" + bone.Node.Name;

            Rbx2Source.ScheduleTasks(task);

            Node     node = bone.Node;
            BasePart part = bone.Part1;

            bool   isAvatarLimb = bone.IsAvatarBone;
            string matName      = part.Name;

            if (isAvatarLimb)
            {
                Limb limb = GetLimb(part);
                matName = Rbx2Source.GetEnumName(limb);
            }

            Material material = new Material();

            material.UseAvatarMap = isAvatarLimb;

            Rbx2Source.Print("Building Geometry for {0}", part.Name);
            Rbx2Source.IncrementStack();

            Mesh geometry = Mesh.BakePart(part, material);

            meshBuilder.Materials[matName] = material;

            for (int i = 0; i < geometry.NumFaces; i++)
            {
                Triangle tri = new Triangle()
                {
                    Node      = node,
                    FaceIndex = i,
                    Mesh      = geometry,
                    Material  = matName
                };

                meshBuilder.Triangles.Add(tri);
            }

            Rbx2Source.DecrementStack();
            Rbx2Source.MarkTaskCompleted(task);
        }
Beispiel #16
0
        public TextureBindings BindTextures(TextureCompositor compositor, Dictionary <string, ValveMaterial> materials)
        {
            Contract.Requires(compositor != null && materials != null);
            TextureBindings textureBinds = new TextureBindings();

            Bitmap uvMap = compositor.BakeTextureMap();

            Rbx2Source.SetDebugImage(uvMap);

            foreach (string matName in materials.Keys)
            {
                Rbx2Source.Print("Building Material {0}", matName);
                ValveMaterial material = materials[matName];
                Image         image    = null;

                if (material.UseAvatarMap)
                {
                    if (Enum.TryParse(matName, out BodyPart limb))
                    {
                        Rectangle cropRegion = UVCrops[limb];
                        image = TextureCompositor.CropBitmap(uvMap, cropRegion);
                    }
                }
                else
                {
                    Asset texture = material.TextureAsset;

                    if (texture != null)
                    {
                        byte[]       textureData   = texture.GetContent();
                        MemoryStream textureStream = new MemoryStream(textureData);

                        image = Image.FromStream(textureStream);
                        textureStream.Dispose();
                    }
                }

                textureBinds.BindTexture(matName, image);
            }

            return(textureBinds);
        }
Beispiel #17
0
        public Task RunWithOutput()
        {
            Process      process = Run();
            StreamReader output  = process.StandardOutput;

            Task runTask = Task.Run(() =>
            {
                while (true)
                {
                    Task <string> nextLineAsync = output.ReadLineAsync();
                    nextLineAsync.Wait(1000);

                    string nextLine = nextLineAsync.Result;
                    if (nextLine == null)
                    {
                        break;
                    }

                    Rbx2Source.Print(nextLine);
                }
            });

            return(runTask);
        }
        public AssemblerData Assemble(UserAvatar avatar)
        {
            Contract.Requires(avatar != null);

            UserInfo userInfo = avatar.UserInfo;
            string   userName = FileUtility.MakeNameWindowsSafe(userInfo.Username);

            string appData = Environment.GetEnvironmentVariable("LocalAppData");
            string rbx2Src = Path.Combine(appData, "Rbx2Source");
            string avatars = Path.Combine(rbx2Src, "Avatars");
            string userBin = Path.Combine(avatars, userName);

            string modelDir     = Path.Combine(userBin, "Model");
            string anim8Dir     = Path.Combine(modelDir, "Animations");
            string texturesDir  = Path.Combine(userBin, "Textures");
            string materialsDir = Path.Combine(userBin, "Materials");

            FileUtility.InitiateEmptyDirectories(modelDir, anim8Dir, texturesDir, materialsDir);

            AvatarType          avatarType = avatar.PlayerAvatarType;
            ICharacterAssembler assembler;

            if (avatarType == AvatarType.R15)
            {
                assembler = new R15CharacterAssembler();
            }
            else
            {
                assembler = new R6CharacterAssembler();
            }

            string compileDir = "roblox_avatars/" + userName;

            string avatarTypeName  = Rbx2Source.GetEnumName(avatarType);
            Folder characterAssets = AppendCharacterAssets(avatar, avatarTypeName);

            Rbx2Source.ScheduleTasks
            (
                "BuildCharacter",
                "BuildCollisionModel",
                "BuildAnimations",
                "BuildTextures",
                "BuildMaterials",
                "BuildCompilerScript"
            );

            Rbx2Source.PrintHeader("BUILDING CHARACTER MODEL");
            #region Build Character Model
            ///////////////////////////////////////////////////////////////////////////////////////////////////////

            StudioMdlWriter writer = assembler.AssembleModel(characterAssets, avatar.Scales, DEBUG_RAPID_ASSEMBLY);

            string studioMdl = writer.BuildFile();
            string modelPath = Path.Combine(modelDir, "CharacterModel.smd");
            FileUtility.WriteFile(modelPath, studioMdl);

            string staticPose = writer.BuildFile(false);
            string refPath    = Path.Combine(modelDir, "ReferencePos.smd");
            FileUtility.WriteFile(refPath, staticPose);

            Rbx2Source.MarkTaskCompleted("BuildCharacter");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            Rbx2Source.PrintHeader("BUILDING COLLISION MODEL");
            #region Build Character Collisions
            ///////////////////////////////////////////////////////////////////////////////////////////////////////

            Folder          collisionAssets = AppendCollisionAssets(avatar, avatarTypeName);
            StudioMdlWriter collisionWriter = assembler.AssembleModel(collisionAssets, avatar.Scales, true);

            string collisionModel = collisionWriter.BuildFile();
            string cmodelPath     = Path.Combine(modelDir, "CollisionModel.smd");
            FileUtility.WriteFile(cmodelPath, collisionModel);

            byte[] collisionJoints = assembler.CollisionModelScript;
            string cjointsPath     = Path.Combine(modelDir, "CollisionJoints.qc");

            FileUtility.WriteFile(cjointsPath, collisionJoints);
            Rbx2Source.MarkTaskCompleted("BuildCollisionModel");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            Rbx2Source.PrintHeader("BUILDING CHARACTER ANIMATIONS");
            #region Build Character Animations
            ///////////////////////////////////////////////////////////////////////////////////////////////////////

            var animIds      = assembler.CollectAnimationIds(avatar);
            var compileAnims = new Dictionary <string, Asset>();

            if (animIds.Count > 0)
            {
                Rbx2Source.Print("Collecting Animations...");
                Rbx2Source.IncrementStack();

                Action <string, Asset> collectAnimation = (animName, animAsset) =>
                {
                    if (!compileAnims.ContainsKey(animName))
                    {
                        Rbx2Source.Print("Collected animation {0} with id {1}", animName, animAsset.Id);
                        compileAnims.Add(animName, animAsset);
                    }
                };

                foreach (string animName in animIds.Keys)
                {
                    var animId    = animIds[animName];
                    var animAsset = animId.GetAsset();
                    var import    = animAsset.OpenAsModel();

                    if (animId.AnimationType == AnimationType.R15AnimFolder)
                    {
                        Folder r15Anim = import.FindFirstChild <Folder>("R15Anim");

                        if (r15Anim != null)
                        {
                            foreach (Instance animDef in r15Anim.GetChildren())
                            {
                                if (animDef.Name == "idle")
                                {
                                    var anims = animDef.GetChildrenOfType <Animation>();

                                    if (anims.Length == 2)
                                    {
                                        var getLookAnim = anims.OrderBy((anim) =>
                                        {
                                            var weight = anim.FindFirstChild <NumberValue>("Weight");

                                            if (weight != null)
                                            {
                                                return(weight.Value);
                                            }

                                            return(0.0);
                                        });

                                        var lookAnim = getLookAnim.First();
                                        lookAnim.Destroy();

                                        Asset lookAsset = Asset.GetByAssetId(lookAnim.AnimationId);
                                        collectAnimation("Idle2", lookAsset);
                                    }
                                }

                                Animation compileAnim = animDef.FindFirstChildOfClass <Animation>();

                                if (compileAnim != null)
                                {
                                    Asset  compileAsset = Asset.GetByAssetId(compileAnim.AnimationId);
                                    string compileName  = animName;

                                    if (animDef.Name == "pose")
                                    {
                                        compileName = "Pose";
                                    }

                                    collectAnimation(compileName, compileAsset);
                                }
                            }
                        }
                    }
                    else
                    {
                        collectAnimation(animName, animAsset);
                    }
                }

                Rbx2Source.DecrementStack();
            }
            else
            {
                Rbx2Source.Print("No animations found :(");
            }

            if (compileAnims.Count > 0)
            {
                Rbx2Source.Print("Assembling Animations...");
                Rbx2Source.IncrementStack();

                foreach (string animName in compileAnims.Keys)
                {
                    Rbx2Source.Print("Building Animation {0}...", animName);

                    Asset animAsset = compileAnims[animName];
                    var   import    = animAsset.OpenAsModel();

                    var sequence = import.FindFirstChildOfClass <KeyframeSequence>();
                    sequence.Name = animName;

                    var avatarTypeRef = new StringValue()
                    {
                        Value  = $"{avatarType}",
                        Name   = "AvatarType",
                        Parent = sequence
                    };

                    string animation = AnimationBuilder.Assemble(sequence, writer.Skeleton[0].Bones);
                    string animPath  = Path.Combine(anim8Dir, animName + ".smd");

                    FileUtility.WriteFile(animPath, animation);
                }

                Rbx2Source.DecrementStack();
            }

            Rbx2Source.MarkTaskCompleted("BuildAnimations");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            Rbx2Source.PrintHeader("BUILDING CHARACTER TEXTURES");
            #region Build Character Textures
            ///////////////////////////////////////////////////////////////////////////////////////////////////////

            var             materials = writer.Materials;
            TextureBindings textures;

            if (DEBUG_RAPID_ASSEMBLY)
            {
                textures = new TextureBindings();
                materials.Clear();
            }
            else
            {
                TextureCompositor texCompositor = assembler.ComposeTextureMap(characterAssets, avatar.BodyColors);
                textures = assembler.BindTextures(texCompositor, materials);
            }

            var images = textures.Images;
            textures.MaterialDirectory = compileDir;

            foreach (string imageName in images.Keys)
            {
                Rbx2Source.Print("Writing Image {0}.png", imageName);

                Image  image     = images[imageName];
                string imagePath = Path.Combine(texturesDir, imageName + ".png");

                try
                {
                    image.Save(imagePath, ImageFormat.Png);
                }
                catch
                {
                    Rbx2Source.Print("IMAGE {0}.png FAILED TO SAVE!", imageName);
                }

                FileUtility.LockFile(imagePath);
            }

            CompositData.FreeAllocatedTextures();
            Rbx2Source.MarkTaskCompleted("BuildTextures");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            Rbx2Source.PrintHeader("WRITING MATERIAL FILES");
            #region Write Material Files
            ///////////////////////////////////////////////////////////////////////////////////////////////////////

            var matLinks = textures.MatLinks;

            foreach (string mtlName in matLinks.Keys)
            {
                Rbx2Source.Print("Building VMT {0}.vmt", mtlName);

                string targetVtf = matLinks[mtlName];
                string vmtPath   = Path.Combine(materialsDir, mtlName + ".vmt");

                ValveMaterial mtl = materials[mtlName];
                mtl.SetVmtField("basetexture", "models/" + compileDir + "/" + targetVtf);
                mtl.WriteVmtFile(vmtPath);
            }

            Rbx2Source.MarkTaskCompleted("BuildMaterials");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            Rbx2Source.PrintHeader("WRITING COMPILER SCRIPT");
            #region Write Compiler Script
            ///////////////////////////////////////////////////////////////////////////////////////////////////////

            string       modelName = compileDir + ".mdl";
            QuakeCWriter qc        = new QuakeCWriter();

            qc.Add("body", userName, "CharacterModel.smd");
            qc.Add("modelname", modelName);
            qc.Add("upaxis", "y");

            // Compute the floor level of the avatar.
            Folder assembly = characterAssets.FindFirstChild <Folder>("ASSEMBLY");

            if (assembly != null)
            {
                float  floor  = ComputeFloorLevel(assembly);
                string origin = "0 " + floor.ToInvariantString() + " 0";
                qc.Add("origin", origin);
            }

            qc.Add("cdmaterials", "models/" + compileDir);
            qc.Add("surfaceprop", "flesh");
            qc.Add("include", "CollisionJoints.qc");

            QuakeCItem refAnim = qc.Add("sequence", "reference", "ReferencePos.smd");
            refAnim.AddSubItem("fps", 1);
            refAnim.AddSubItem("loop");

            foreach (string animName in compileAnims.Keys)
            {
                QuakeCItem sequence = qc.Add("sequence", animName.ToLowerInvariant(), "Animations/" + animName + ".smd");
                sequence.AddSubItem("fps", AnimationBuilder.FrameRate);

                if (avatarType == AvatarType.R6)
                {
                    sequence.AddSubItem("delta");
                }

                sequence.AddSubItem("loop");
            }

            string qcFile = qc.ToString();
            string qcPath = Path.Combine(modelDir, "Compile.qc");

            FileUtility.WriteFile(qcPath, qcFile);
            Rbx2Source.MarkTaskCompleted("BuildCompilerScript");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            AssemblerData data = new AssemblerData()
            {
                ModelData      = writer,
                ModelName      = modelName,
                TextureData    = textures,
                CompilerScript = qcPath,

                RootDirectory     = userBin,
                CompileDirectory  = compileDir,
                TextureDirectory  = texturesDir,
                MaterialDirectory = materialsDir,
            };

            return(data);
        }
        public AssemblerData Assemble(object metadata)
        {
            UserAvatar avatar = metadata as UserAvatar;

            if (avatar == null)
            {
                throw new Exception("bad cast");
            }

            UserInfo userInfo = avatar.UserInfo;
            string   userName = FileUtility.MakeNameWindowsSafe(userInfo.Username);

            string appData    = Environment.GetEnvironmentVariable("AppData");
            string rbx2Source = Path.Combine(appData, "Rbx2Source");
            string avatars    = Path.Combine(rbx2Source, "Avatars");
            string userBin    = Path.Combine(avatars, userName);

            string modelDir     = Path.Combine(userBin, "Model");
            string animDir      = Path.Combine(modelDir, "Animations");
            string texturesDir  = Path.Combine(userBin, "Textures");
            string materialsDir = Path.Combine(userBin, "Materials");

            FileUtility.InitiateEmptyDirectories(modelDir, animDir, texturesDir, materialsDir);

            AvatarType          avatarType = avatar.ResolvedAvatarType;
            ICharacterAssembler assembler;

            if (avatarType == AvatarType.R15)
            {
                assembler = new R15CharacterAssembler();
            }
            else
            {
                assembler = new R6CharacterAssembler();
            }

            string avatarTypeName  = Rbx2Source.GetEnumName(avatar.ResolvedAvatarType);
            Folder characterAssets = AppendCharacterAssets(avatar, avatarTypeName);

            Rbx2Source.ScheduleTasks("BuildCharacter", "BuildCollisionModel", "BuildAnimations", "BuildTextures", "BuildMaterials", "BuildCompilerScript");
            Rbx2Source.PrintHeader("BUILDING CHARACTER MODEL");

            StudioMdlWriter writer = assembler.AssembleModel(characterAssets, avatar.Scales);

            string studioMdl = writer.BuildFile();
            string modelPath = Path.Combine(modelDir, "CharacterModel.smd");

            FileUtility.WriteFile(modelPath, studioMdl);

            // Clear the triangles so we can build a reference pose .smd file.
            writer.Triangles.Clear();
            string staticPose = writer.BuildFile();
            string refPath    = Path.Combine(modelDir, "ReferencePos.smd");

            FileUtility.WriteFile(refPath, staticPose);
            Rbx2Source.MarkTaskCompleted("BuildCharacter");

            Rbx2Source.PrintHeader("BUILDING COLLISION MODEL");

            Folder lowPoly = new Folder();

            SpecialMesh lowPolyHead = new SpecialMesh();

            lowPolyHead.MeshId   = "rbxassetid://582002794";
            lowPolyHead.MeshType = MeshType.FileMesh;
            lowPolyHead.Scale    = new Vector3(1, 1, 1);
            lowPolyHead.Offset   = new Vector3();
            lowPolyHead.Parent   = lowPoly;

            StudioMdlWriter collisionWriter = assembler.AssembleModel(lowPoly, avatar.Scales);

            string collisionModel = collisionWriter.BuildFile();
            string cmodelPath     = Path.Combine(modelDir, "CollisionModel.smd");

            FileUtility.WriteFile(cmodelPath, collisionModel);

            byte[] collisionJoints = assembler.CollisionModelScript;
            string cjointsPath     = Path.Combine(modelDir, "CollisionJoints.qc");

            FileUtility.WriteFile(cjointsPath, collisionJoints);
            Rbx2Source.MarkTaskCompleted("BuildCollisionModel");

            Rbx2Source.PrintHeader("BUILDING CHARACTER ANIMATIONS");
            Dictionary <string, string> animations = GatherAnimations(avatarType);

            if (animations.Count > 0)
            {
                foreach (string animName in animations.Keys)
                {
                    Rbx2Source.Print("Building Animation {0}", animName);
                    string           localAnimPath = animations[animName];
                    Asset            animAsset     = Asset.FromResource(localAnimPath);
                    Folder           import        = RBXM.LoadFromAsset(animAsset);
                    KeyframeSequence sequence      = import.FindFirstChildOfClass <KeyframeSequence>();
                    sequence.Name       = animName;
                    sequence.AvatarType = avatarType;
                    string animation = AnimationAssembler.Assemble(sequence, writer.Skeleton[0].Bones);
                    string animPath  = Path.Combine(animDir, animName + ".smd");
                    FileUtility.WriteFile(animPath, animation);
                }
            }
            else
            {
                Rbx2Source.Print("No animations found :(");
            }

            Rbx2Source.MarkTaskCompleted("BuildAnimations");
            Dictionary <string, Material> materials = writer.Materials;

            Rbx2Source.PrintHeader("BUILDING CHARACTER TEXTURES");

            string compileDirectory = "roblox_avatars/" + userName;

            TextureCompositor texCompositor = assembler.ComposeTextureMap(characterAssets, avatar.BodyColors);
            TextureAssembly   texAssembly   = assembler.AssembleTextures(texCompositor, materials);

            CompositData.FreeAllocatedTextures();
            texAssembly.MaterialDirectory = compileDirectory;

            Dictionary <string, Image> images = texAssembly.Images;

            foreach (string imageName in images.Keys)
            {
                Rbx2Source.Print("Writing Image {0}.png", imageName);
                Image  image     = images[imageName];
                string imagePath = Path.Combine(texturesDir, imageName + ".png");
                try
                {
                    image.Save(imagePath, ImageFormat.Png);
                }
                catch
                {
                    Rbx2Source.Print("IMAGE {0}.png FAILED TO SAVE!", imageName);
                }
                FileUtility.LockFile(imagePath);
            }

            Rbx2Source.MarkTaskCompleted("BuildTextures");
            Rbx2Source.PrintHeader("BUILDING MATERIAL FILES");

            Dictionary <string, string> matLinks = texAssembly.MatLinks;

            foreach (string mtlName in matLinks.Keys)
            {
                Rbx2Source.Print("Building VMT {0}.vmt", mtlName);
                string        targetVtf = matLinks[mtlName];
                Material      mtl       = materials[mtlName];
                ValveMaterial vmt       = new ValveMaterial(mtl);
                vmt.SetField("basetexture", "models/" + compileDirectory + "/" + targetVtf);
                string vmtPath    = Path.Combine(materialsDir, mtlName + ".vmt");
                string vmtContent = vmt.ToString();
                FileUtility.WriteFile(vmtPath, vmtContent);
            }

            Rbx2Source.MarkTaskCompleted("BuildMaterials");
            Rbx2Source.PrintHeader("WRITING COMPILER SCRIPT");

            QCWriter qc = new QCWriter();

            QCommand model = new QCommand("body", userName, "CharacterModel.smd");

            qc.AddCommand(model);

            string modelNameStr = compileDirectory + ".mdl";

            qc.WriteBasicCmd("modelname", modelNameStr);
            qc.WriteBasicCmd("upaxis", "y");

            string originStr = "";

            if (avatarType == AvatarType.R6)
            {
                originStr = "0 -30 0";
            }
            else
            {
                originStr = "0 " + (-23.5 * avatar.Scales.Height).ToString(Rbx2Source.NormalParse) + " 0";
            }

            qc.WriteBasicCmd("origin", originStr, false);
            qc.WriteBasicCmd("cdmaterials", "models/" + compileDirectory);
            qc.WriteBasicCmd("surfaceprop", "flesh");
            qc.WriteBasicCmd("include", "CollisionJoints.qc");

            QCommand reference = new QCommand("sequence", "reference", "ReferencePos.smd");

            reference.AddParameter("fps", "1");
            reference.AddParameter("loop");
            qc.AddCommand(reference);

            foreach (string animName in animations.Keys)
            {
                QCommand sequence = new QCommand("sequence", animName.ToLower(), "Animations/" + animName + ".smd");
                sequence.AddParameter("fps", AnimationAssembler.FrameRate.ToString());
                sequence.AddParameter("loop");
                if (avatarType == AvatarType.R6) // TODO: Find a work around so I can get rid of this.
                {
                    sequence.AddParameter("delta");
                }

                qc.AddCommand(sequence);
            }

            string qcFile = qc.BuildFile();
            string qcPath = Path.Combine(modelDir, "Compile.qc");

            FileUtility.WriteFile(qcPath, qcFile);
            Rbx2Source.MarkTaskCompleted("BuildCompilerScript");

            AssemblerData data = new AssemblerData();

            data.ModelData         = writer;
            data.TextureData       = texAssembly;
            data.CompilerScript    = qcPath;
            data.RootDirectory     = userBin;
            data.MaterialDirectory = materialsDir;
            data.TextureDirectory  = texturesDir;
            data.CompileDirectory  = compileDirectory;
            data.ModelName         = modelNameStr;

            return(data);
        }
Beispiel #20
0
        public static Asset Get(long assetId, string idPiece = "/asset/?ID=")
        {
            if (!assetCache.ContainsKey(assetId))
            {
                string appData = Environment.GetEnvironmentVariable("LocalAppData");

                string assetCacheDir = Path.Combine(appData, "Rbx2Source", "AssetCache");
                Directory.CreateDirectory(assetCacheDir);

                // Ping Roblox to figure out what this asset's cdn url is
                Uri            uri  = new Uri("https://assetdelivery.roblox.com/v1" + idPiece + assetId);
                HttpWebRequest ping = WebRequest.CreateHttp(uri);
                ping.UserAgent         = "RobloxStudio/WinInet";
                ping.AllowAutoRedirect = false;

                Asset asset = null;

                string location   = "";
                string identifier = "";
                string cachedFile = "";

                try
                {
                    using (var response = ping.GetResponse() as HttpWebResponse)
                    {
                        location   = response.GetResponseHeader("Location");
                        identifier = location.Remove(0, 8).Replace(".rbxcdn.com/", "-");
                        cachedFile = assetCacheDir + '\\' + identifier.Replace('/', '\\');

                        if (File.Exists(cachedFile))
                        {
                            string cachedContent = File.ReadAllText(cachedFile);

                            try
                            {
                                asset = JsonConvert.DeserializeObject <Asset>(cachedContent);

                                if (asset.Content.Length == 0)
                                {
                                    asset = null;
                                    throw new Exception();
                                }

                                Rbx2Source.Print("Fetched pre-cached asset {0}", assetId);
                            }
                            catch
                            {
                                // Corrupted file?
                                if (File.Exists(cachedFile))
                                {
                                    Rbx2Source.Print("Deleting corrupted file {0}", cachedFile);
                                    File.Delete(cachedFile);
                                }
                            }
                        }
                    }
                }
                catch
                {
                    Console.WriteLine("Failed to fetch {0}?", assetId);
                }

                if (asset == null)
                {
                    WebClient http = new WebClient()
                    {
                        UseDefaultCredentials = true,
                        Proxy = null
                    };

                    http.Headers.Set(HttpRequestHeader.UserAgent, "RobloxStudio/WinInet");
                    asset = new Asset()
                    {
                        Id = assetId
                    };

                    try
                    {
                        string productInfoJson = http.DownloadString("http://api.roblox.com/marketplace/productinfo?assetId=" + assetId);
                        asset.ProductInfo = JsonConvert.DeserializeObject <ProductInfo>(productInfoJson);
                        asset.ProductInfo.WindowsSafeName = FileUtility.MakeNameWindowsSafe(asset.ProductInfo.Name);
                        asset.AssetType = asset.ProductInfo.AssetTypeId;
                    }
                    catch
                    {
                        string name = "unknown_" + asset.Id;

                        ProductInfo dummyInfo = new ProductInfo()
                        {
                            Name            = name,
                            WindowsSafeName = name,
                            AssetTypeId     = AssetType.Model
                        };

                        asset.ProductInfo = dummyInfo;
                    }

                    asset.CdnUrl     = location;
                    asset.CdnCacheId = identifier;
                    asset.GetContent();
                    asset.Loaded = true;

                    string serialized = JsonConvert.SerializeObject(asset, Formatting.None);

                    try
                    {
                        File.WriteAllText(cachedFile, serialized);
                        Rbx2Source.Print("Precached AssetId {0}", assetId);
                    }
                    catch
                    {
                        // Oh well.
                        Rbx2Source.Print("Failed to cache AssetId {0}", assetId);
                    }

                    http.Dispose();
                }

                assetCache[assetId] = asset;
            }

            return(assetCache[assetId]);
        }
        public TextureBindings BindTextures(TextureCompositor compositor, Dictionary <string, ValveMaterial> materials)
        {
            Contract.Requires(compositor != null && materials != null);
            TextureBindings textures = new TextureBindings();

            Bitmap core = compositor.BakeTextureMap();

            Rbx2Source.SetDebugImage(core);

            Bitmap head = TextureCompositor.CropBitmap(core, RECT_HEAD);

            textures.BindTexture("Head", head);

            Bitmap body            = TextureCompositor.CropBitmap(core, RECT_BODY);
            Folder characterAssets = compositor.CharacterAssets;

            Rbx2Source.Print("Processing Package Textures...");
            Rbx2Source.IncrementStack();

            // Collect CharacterMeshes
            var packagedLimbs = characterAssets
                                .GetChildrenOfType <CharacterMesh>()
                                .ToDictionary(mesh => mesh.BodyPart);

            // Compose the textures that will be used
            var limbOverlays = new Dictionary <BodyPart, long>();
            var limbBitmaps  = new Dictionary <long, Bitmap>()
            {
                { 0, body }
            };

            foreach (BodyPart limb in LimbMatcher.Keys)
            {
                // Head is already textured, ignore it.
                if (limb == BodyPart.Head)
                {
                    continue;
                }

                // Is there a CharacterMesh for this limb?
                if (packagedLimbs.ContainsKey(limb))
                {
                    // Check the CharacterMesh textures.
                    CharacterMesh mesh = packagedLimbs[limb];

                    if (mesh.OverlayTextureId > 0)
                    {
                        // Use the overlay texture for this limb.
                        long overlayId = mesh.OverlayTextureId;
                        limbOverlays.Add(limb, overlayId);

                        // Compose this overlay texture with the body texture if it doesn't exist yet.
                        if (!limbBitmaps.ContainsKey(overlayId))
                        {
                            Asset overlayAsset = Asset.Get(overlayId);

                            TextureCompositor overlayCompositor = new TextureCompositor(AvatarType.R6, RECT_FULL);
                            overlayCompositor.SetContext("Overlay Texture " + overlayId);
                            overlayCompositor.AppendTexture(overlayAsset, RECT_BODY, 1);
                            overlayCompositor.AppendTexture(body, RECT_BODY);

                            Bitmap overlayTex = overlayCompositor.BakeTextureMap(RECT_BODY);
                            limbBitmaps.Add(overlayId, overlayTex);
                        }

                        continue;
                    }
                    else if (mesh.BaseTextureId > 0)
                    {
                        // Use the base texture for this limb.
                        long baseId = mesh.BaseTextureId;
                        limbOverlays.Add(limb, baseId);

                        // Compose the base texture if it doesn't exist yet.
                        if (!limbBitmaps.ContainsKey(baseId))
                        {
                            Asset baseAsset = Asset.Get(baseId);

                            TextureCompositor baseCompositor = new TextureCompositor(AvatarType.R6, RECT_FULL);
                            baseCompositor.SetContext("Base Texture " + baseId);
                            baseCompositor.AppendTexture(baseAsset, RECT_BODY);

                            Bitmap baseTex = baseCompositor.BakeTextureMap(RECT_BODY);
                            limbBitmaps.Add(baseId, baseTex);
                        }

                        continue;
                    }
                }

                // If no continue statement is reached, fallback to using the body texture.
                // This occurs if the limb has no package, or the package limb has no textures.
                limbOverlays.Add(limb, 0);
            }

            // Add the images into the texture assembly.
            foreach (long id in limbBitmaps.Keys)
            {
                Bitmap bitmap  = limbBitmaps[id];
                string matName = GetBodyMatName(id);
                textures.BindTexture(matName, bitmap, false);
            }

            // Link the limbs to their textures.
            foreach (BodyPart limb in limbOverlays.Keys)
            {
                long   id      = limbOverlays[limb];
                string matName = GetBodyMatName(id);

                string limbName = Rbx2Source.GetEnumName(limb);
                textures.BindTextureAlias(limbName, matName);
            }

            // Handle the rest of the materials
            foreach (string matName in materials.Keys)
            {
                if (!textures.MatLinks.ContainsKey(matName))
                {
                    ValveMaterial material = materials[matName];
                    Asset         texture  = material.TextureAsset;

                    TextureCompositor matComp = new TextureCompositor(AvatarType.R6, RECT_ITEM);
                    matComp.SetContext("Accessory Texture " + matName);
                    matComp.AppendTexture(texture, RECT_ITEM);

                    Bitmap bitmap = matComp.BakeTextureMap();
                    textures.BindTexture(matName, bitmap);
                }
            }

            Rbx2Source.DecrementStack();
            return(textures);
        }
Beispiel #22
0
 public static void PreScheduleTasks()
 {
     // This is called before the model is built or compiled.
     Rbx2Source.ScheduleTasks("CompileModel", "CompileTextures", "MoveTextures");
 }
Beispiel #23
0
        public static async Task <string> Compile(GameInfo gameInfo, AssemblerData data)
        {
            if (!gameInfo.ReadyToUse)
            {
                throw new Exception("This gameinfo.txt file isn't ready to use!");
            }

            Rbx2Source.PrintHeader("COMPILING MODEL");
            string studioMdlPath = gameInfo.StudioMdlPath;

            ThirdPartyUtility studioMdl = new ThirdPartyUtility(studioMdlPath);

            studioMdl.AddParameter("game", gameInfo.GameDirectory);
            studioMdl.AddParameter("nop4");
            studioMdl.AddParameter(UtilParameter.FilePush(data.CompilerScript));
            await studioMdl.Run();

            Rbx2Source.MarkTaskCompleted("CompileModel");

            Rbx2Source.PrintHeader("COMPILING TEXTURES");
            if (!File.Exists(vtfCompilerPath))
            {
                byte[]       vtfZip  = ResourceUtility.GetResource("VTFCmd.zip");
                MemoryStream extract = new MemoryStream(vtfZip);
                ZipArchive   archive = new ZipArchive(extract);
                foreach (ZipArchiveEntry entry in archive.Entries)
                {
                    string name   = entry.Name;
                    string path   = Path.Combine(utilityDir, name);
                    Stream stream = entry.Open();
                    byte[] file   = FileUtility.ReadFullStream(stream);
                    FileUtility.WriteFile(path, file);
                }
            }

            string pngWildcard = Path.Combine(data.TextureDirectory, "*.png");

            vtfCompiler = new ThirdPartyUtility(vtfCompilerPath);
            vtfCompiler.AddParameter("folder", pngWildcard);
            vtfCompiler.AddParameter("resize");
            vtfCompiler.AddParameter("format", "ABGR8888");             // No compression? THIS IS FINE.png
            vtfCompiler.AddParameter("output", data.MaterialDirectory);
            await vtfCompiler.Run();

            Rbx2Source.MarkTaskCompleted("CompileTextures");

            string gameDirectory = gameInfo.GameDirectory;
            string modelPath     = Path.Combine(gameDirectory, "models", data.ModelName);
            string materialPath  = Path.Combine(gameDirectory, "materials", "models", data.CompileDirectory);

            FileUtility.InitiateEmptyDirectories(materialPath);

            foreach (string filePath in Directory.GetFiles(data.MaterialDirectory))
            {
                FileInfo info         = new FileInfo(filePath);
                string   fileName     = info.Name;
                string   destFileName = Path.Combine(materialPath, fileName);
                info.CopyTo(destFileName);
            }

            Rbx2Source.MarkTaskCompleted("MoveTextures");
            return(modelPath);
        }
        public AssemblerData Assemble(long assetId)
        {
            Asset  asset     = Asset.Get(assetId);
            string assetName = asset.ProductInfo.WindowsSafeName.Trim();

            string appData    = Environment.GetEnvironmentVariable("LocalAppData");
            string rbx2Source = Path.Combine(appData, "Rbx2Source");
            string items      = Path.Combine(rbx2Source, "Items");
            string rootDir    = Path.Combine(items, assetName);

            string modelDir     = Path.Combine(rootDir, "Model");
            string texturesDir  = Path.Combine(rootDir, "Textures");
            string materialsDir = Path.Combine(rootDir, "Materials");

            FileUtility.InitiateEmptyDirectories(modelDir, texturesDir, materialsDir);
            Rbx2Source.ScheduleTasks("BuildModel", "BuildTextures", "BuildMaterials", "BuildCompilerScript");

            Rbx2Source.PrintHeader("BUILDING MODEL");
            #region Build Model
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            StudioMdlWriter writer = AssembleModel(asset);

            string studioMdl = writer.BuildFile();
            string modelPath = Path.Combine(modelDir, "Asset.smd");
            FileUtility.WriteFile(modelPath, studioMdl);

            string reference = writer.BuildFile(false);
            string refPath   = Path.Combine(modelDir, "Reference.smd");
            FileUtility.WriteFile(refPath, reference);

            Rbx2Source.MarkTaskCompleted("BuildModel");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            Rbx2Source.PrintHeader("BUILDING TEXTURES");
            #region Build Textures
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            var materials = writer.Materials;
            var textures  = BindTextures(materials);

            var images     = textures.Images;
            var compileDir = "roblox_assets/" + assetName;

            foreach (string imageName in images.Keys)
            {
                Rbx2Source.Print("Writing Image {0}", imageName);

                Image  image     = images[imageName];
                string imagePath = Path.Combine(texturesDir, imageName + ".png");

                try
                {
                    image.Save(imagePath, ImageFormat.Png);
                }
                catch
                {
                    Rbx2Source.Print("IMAGE {0}.png FAILED TO SAVE!", imageName);
                }

                FileUtility.LockFile(imagePath);
            }

            textures.MaterialDirectory = compileDir;
            Rbx2Source.MarkTaskCompleted("BuildTextures");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            Rbx2Source.PrintHeader("WRITING MATERIAL FILES");
            #region Write Materials
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            string mtlDir   = "models/" + compileDir;
            var    matLinks = textures.MatLinks;

            foreach (string matName in matLinks.Keys)
            {
                string vtfTarget = matLinks[matName];
                string vmtPath   = Path.Combine(materialsDir, matName + ".vmt");

                ValveMaterial mat = materials[matName];
                mat.SetVmtField("basetexture", mtlDir + '/' + vtfTarget);
                mat.WriteVmtFile(vmtPath);
            }

            Rbx2Source.MarkTaskCompleted("BuildMaterials");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            Rbx2Source.PrintHeader("WRITING COMPILER SCRIPT");
            #region Write Compiler Script
            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////

            string       modelName = compileDir + ".mdl";
            QuakeCWriter qc        = new QuakeCWriter();

            qc.Add("body", assetName, "Asset.smd");
            qc.Add("modelname", modelName);
            qc.Add("upaxis", "y");
            qc.Add("cdmaterials", mtlDir);

            QuakeCItem phys = qc.Add("collisionjoints", "Asset.smd");
            phys.AddSubItem("$mass", 115.0);
            phys.AddSubItem("$inertia", 2.00);
            phys.AddSubItem("$damping", 0.01);
            phys.AddSubItem("$rotdamping", 0.40);

            QuakeCItem refAnim = qc.Add("sequence", "reference", "Reference.smd");
            refAnim.AddSubItem("fps", 1);
            refAnim.AddSubItem("loop");

            string qcFile = qc.ToString();
            string qcPath = Path.Combine(modelDir, "Compile.qc");

            FileUtility.WriteFile(qcPath, qcFile);
            Rbx2Source.MarkTaskCompleted("BuildCompilerScript");

            ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
            #endregion

            AssemblerData data = new AssemblerData()
            {
                ModelData      = writer,
                ModelName      = modelName,
                TextureData    = textures,
                CompilerScript = qcPath,

                RootDirectory     = rootDir,
                CompileDirectory  = compileDir,
                TextureDirectory  = texturesDir,
                MaterialDirectory = materialsDir
            };

            return(data);
        }
        public static StudioMdlWriter AssembleModel(Asset asset)
        {
            Contract.Requires(asset != null);

            var content = asset.OpenAsModel();

            Rbx2Source.ScheduleTasks("GatherParts", "BuildMesh");

            List <BasePart> parts = new List <BasePart>();

            AddParts(parts, content);

            if (parts.Count == 0)
            {
                throw new Exception("No parts were found inside of this asset!");
            }

            BasePart primaryPart = null;

            foreach (BasePart part in parts)
            {
                if (part is MeshPart || part.Name == "Handle")
                {
                    primaryPart = part;
                    break;
                }
            }

            if (primaryPart == null) // k lol
            {
                primaryPart = parts[0];
            }

            primaryPart.Name = asset.ProductInfo.WindowsSafeName.Trim();

            // Mark the primaryPart's location as the center.
            CFrame rootCoord = primaryPart.CFrame;

            foreach (BasePart part in parts)
            {
                part.CFrame = rootCoord.ToObjectSpace(part.CFrame);
            }

            Rbx2Source.MarkTaskCompleted("GatherParts");
            Rbx2Source.PrintHeader("BUILDING MESH");

            StudioMdlWriter writer = new StudioMdlWriter();

            BoneKeyframe skeleton = new BoneKeyframe();

            writer.Skeleton.Add(skeleton);

            List <StudioBone> bones = skeleton.Bones;
            List <Node>       nodes = writer.Nodes;

            List <Triangle> triangles         = writer.Triangles;
            int             numAssembledParts = 0;

            var materials  = writer.Materials;
            var nameCounts = new Dictionary <string, int>();

            foreach (BasePart part in parts)
            {
                // Make sure this part has a unique name.
                string name = part.Name;

                if (nameCounts.ContainsKey(name))
                {
                    int count = ++nameCounts[name];
                    name     += count.ToInvariantString();
                    part.Name = name;
                }
                else
                {
                    nameCounts[name] = 0;
                }

                // Assemble the part.
                var  material = new ValveMaterial();
                Mesh geometry = Mesh.BakePart(part, material);

                if (geometry != null && geometry.NumFaces > 0)
                {
                    string task = "BuildGeometry_" + name;
                    Rbx2Source.ScheduleTasks(task);
                    Rbx2Source.Print("Building Geometry for {0}", name);

                    var bone = new StudioBone(name, primaryPart, part)
                    {
                        C0 = part.CFrame
                    };
                    bones.Add(bone);

                    Node node = bone.Node;
                    nodes.Add(node);

                    int faceStride;
                    materials.Add(name, material);

                    if (geometry.HasLODs)
                    {
                        faceStride = geometry.LODs[1];
                    }
                    else
                    {
                        faceStride = geometry.NumFaces;
                    }

                    for (int i = 0; i < faceStride; i++)
                    {
                        Triangle tri = new Triangle()
                        {
                            Node      = node,
                            Mesh      = geometry,
                            FaceIndex = i,
                            Material  = name,
                        };

                        triangles.Add(tri);
                    }

                    Rbx2Source.MarkTaskCompleted(task);
                    numAssembledParts++;
                }
            }


            Rbx2Source.MarkTaskCompleted("BuildMesh");
            return(writer);
        }
Beispiel #26
0
        public StudioMdlWriter AssembleModel(Folder characterAssets, AvatarScale scale, bool collisionModel = false)
        {
            Contract.Requires(characterAssets != null);
            StudioMdlWriter meshBuilder = new StudioMdlWriter();

            // Build Character
            var    import   = R15AssemblyAsset.OpenAsModel();
            Folder assembly = import.FindFirstChild <Folder>("ASSEMBLY");

            BasePart head = assembly.FindFirstChild <BasePart>("Head");

            assembly.Parent = characterAssets;

            foreach (Instance asset in characterAssets.GetChildren())
            {
                if (asset is BasePart)
                {
                    BasePart existing = assembly.FindFirstChild <BasePart>(asset.Name);

                    if (existing != null)
                    {
                        existing.Destroy();
                    }

                    asset.Parent = assembly;
                }
                else if (asset is Folder && asset.Name == "R15ArtistIntent")
                {
                    foreach (BasePart child in asset.GetChildrenOfType <BasePart>())
                    {
                        BasePart existing = assembly.FindFirstChild <BasePart>(child.Name);

                        if (existing != null)
                        {
                            existing.Destroy();
                        }

                        child.Parent = assembly;
                    }
                }
                else if (asset is Accoutrement && !collisionModel)
                {
                    PrepareAccessory(asset, assembly);
                }
                else if (asset is DataModelMesh)
                {
                    OverwriteHead(asset as DataModelMesh, head);
                }
            }

            // Apply limb scaling
            var parts     = assembly.GetChildrenOfType <BasePart>();
            var attachMap = new Dictionary <string, Attachment>();

            var avatarParts = parts.Where((part) =>
            {
                var limb = GetLimb(part);
                return(limb.HasValue);
            });

            var accessoryParts = parts.Except(avatarParts);

            foreach (BasePart avatarPart in avatarParts)
            {
                Vector3 limbScale = ComputeLimbScale(scale, avatarPart);

                foreach (Attachment att in avatarPart.GetChildrenOfType <Attachment>())
                {
                    attachMap[att.Name] = att;
                }

                ScalePart(avatarPart, limbScale);
            }

            // Apply accessory scaling
            foreach (BasePart handle in accessoryParts)
            {
                Attachment handleAtt = handle.FindFirstChildOfClass <Attachment>();

                if (handleAtt != null)
                {
                    string attName = handleAtt.Name;

                    if (attachMap.ContainsKey(attName))
                    {
                        Attachment avatarAtt  = attachMap[attName];
                        BasePart   avatarPart = avatarAtt.Parent as BasePart;

                        Vector3 accessoryScale = ComputeAccessoryScale(scale, avatarPart, handle);
                        ScalePart(handle, accessoryScale);
                    }
                }
            }

            BasePart torso = assembly.FindFirstChild <BasePart>("LowerTorso");

            torso.CFrame = new CFrame();

            BoneKeyframe      keyframe = AssembleBones(meshBuilder, torso);
            List <StudioBone> bones    = keyframe.Bones;

            // Build File Data.
            Rbx2Source.Print("Building Geometry...");
            Rbx2Source.IncrementStack();

            foreach (StudioBone bone in bones)
            {
                BuildAvatarGeometry(meshBuilder, bone);
            }

            Rbx2Source.DecrementStack();
            return(meshBuilder);
        }
Beispiel #27
0
        public static Asset Get(long assetId, string idPiece = "/asset/?ID=")
        {
            if (!assetCache.ContainsKey(assetId))
            {
                string appData       = Environment.GetEnvironmentVariable("AppData");
                string assetCacheDir = Path.Combine(appData, "Rbx2Source", "AssetCache");
                Directory.CreateDirectory(assetCacheDir);

                // Ping Roblox to figure out what this asset's cdn url is
                HttpWebRequest ping = WebRequest.CreateHttp("https://assetgame.roblox.com" + idPiece + assetId);
                ping.UserAgent         = "Roblox";
                ping.Method            = "HEAD";
                ping.AllowAutoRedirect = false;

                HttpWebResponse response   = (HttpWebResponse)ping.GetResponse();
                string          location   = response.GetResponseHeader("Location");
                string          identifier = location.Remove(0, 7).Replace(".rbxcdn.com/", "-") + "_64";
                string          cachedFile = Path.Combine(assetCacheDir, identifier);
                response.Close();

                Asset asset = null;
                if (File.Exists(cachedFile))
                {
                    string cachedContent = File.ReadAllText(cachedFile);
                    try
                    {
                        asset = JsonConvert.DeserializeObject <Asset>(cachedContent);
                        Rbx2Source.Print("Fetched pre-cached asset {0}", assetId);
                    }
                    catch
                    {
                        // Corrupted file?
                        if (File.Exists(cachedFile))
                        {
                            File.Delete(cachedFile);
                        }
                    }
                }

                if (asset == null)
                {
                    asset = new Asset();

                    WebClient http = new WebClient();
                    http.UseDefaultCredentials = true;
                    http.Headers.Set(HttpRequestHeader.UserAgent, "Roblox");
                    http.Proxy = null;
                    asset.Id   = assetId;

                    try
                    {
                        string productInfoJson = http.DownloadString("http://api.roblox.com/marketplace/productinfo?assetId=" + assetId);
                        asset.ProductInfo = JsonConvert.DeserializeObject <ProductInfo>(productInfoJson);
                        asset.ProductInfo.WindowsSafeName = FileUtility.MakeNameWindowsSafe(asset.ProductInfo.Name);
                        asset.AssetType = asset.ProductInfo.AssetTypeId;
                    }
                    catch
                    {
                        ProductInfo dummyInfo = new ProductInfo();
                        dummyInfo.Name            = "unknown_" + asset.Id;
                        dummyInfo.WindowsSafeName = dummyInfo.Name;
                        dummyInfo.AssetTypeId     = AssetType.Model;
                    }

                    asset.CdnUrl     = location;
                    asset.CdnCacheId = identifier;
                    asset.GetContent();
                    asset.Loaded = true;

                    string serialized = JsonConvert.SerializeObject(asset, Formatting.None, new JsonSerializerSettings());
                    try
                    {
                        File.WriteAllText(cachedFile, serialized);
                        Rbx2Source.Print("Precached AssetId {0}", assetId);
                    }
                    catch
                    {
                        // Oh well.
                        Rbx2Source.Print("Failed to cache AssetId {0}", assetId);
                    }
                }

                assetCache[assetId] = asset;
            }

            return(assetCache[assetId]);
        }
        public StudioMdlWriter AssembleModel(Folder characterAssets, AvatarScale scale)
        {
            StudioMdlWriter meshBuilder = new StudioMdlWriter();

            // Build Character
            Folder import   = RBXM.LoadFromAsset(R15AssemblyAsset);
            Folder assembly = import.FindFirstChild <Folder>("ASSEMBLY");

            assembly.Parent = characterAssets;

            Part    head        = assembly.FindFirstChild <Part>("Head");
            Vector3 avatarScale = GetAvatarScale(scale);

            foreach (Instance asset in characterAssets.GetChildren())
            {
                if (asset.IsA("Part"))
                {
                    Part existing = assembly.FindFirstChild <Part>(asset.Name);
                    if (existing != null)
                    {
                        existing.Destroy();
                    }

                    asset.Parent = assembly;
                }
                else if (asset.IsA("Accoutrement"))
                {
                    PrepareAccessory(asset, assembly);
                }
                else if (asset.IsA("DataModelMesh"))
                {
                    OverwriteHead(asset, head);
                }
            }

            // Avatar Scaling

            foreach (Part part in assembly.GetChildrenOfClass <Part>())
            {
                Limb limb = GetLimb(part);
                if (limb != Limb.Unknown)
                {
                    part.Size *= avatarScale;

                    foreach (Attachment attachment in part.GetChildrenOfClass <Attachment>())
                    {
                        attachment.CFrame = CFrame.Scale(attachment.CFrame, avatarScale);
                    }
                }
            }

            Part torso = assembly.FindFirstChild <Part>("LowerTorso");

            torso.CFrame = new CFrame();

            BoneKeyframe keyframe = AssembleBones(meshBuilder, torso);
            List <Bone>  bones    = keyframe.Bones;

            // Build File Data.
            Rbx2Source.Print("Building Geometry...");
            Rbx2Source.IncrementStack();
            foreach (Bone bone in bones)
            {
                BuildAvatarGeometry(meshBuilder, bone);
            }

            Rbx2Source.DecrementStack();
            return(meshBuilder);
        }
        public TextureAssembly AssembleTextures(TextureCompositor compositor, Dictionary <string, Material> materials)
        {
            TextureAssembly assembly = new TextureAssembly();

            assembly.Images   = new Dictionary <string, Image>();
            assembly.MatLinks = new Dictionary <string, string>();

            Bitmap uvMap = compositor.BakeTextureMap();

            Rbx2Source.SetDebugImage(uvMap);

            ImageAttributes blankAtt = new ImageAttributes();

            foreach (string materialName in materials.Keys)
            {
                Rbx2Source.Print("Building Material {0}", materialName);
                Material material = materials[materialName];
                Image    image    = null;
                if (material.UseAvatarMap)
                {
                    Limb limb;
                    if (Enum.TryParse(materialName, out limb))
                    {
                        Rectangle cropRegion = UVCrops[limb];

                        Size size = cropRegion.Size;
                        int  w    = size.Width;
                        int  h    = size.Height;

                        Point origin = cropRegion.Location;
                        int   x      = origin.X;
                        int   y      = origin.Y;

                        Bitmap    newImg   = new Bitmap(w, h);
                        Graphics  graphics = Graphics.FromImage(newImg);
                        Rectangle dest     = new Rectangle(Point.Empty, size);

                        graphics.DrawImage(uvMap, dest, x, y, w, h, GraphicsUnit.Pixel, blankAtt);
                        graphics.Dispose();

                        image = newImg;
                    }
                }
                else
                {
                    Asset texture = material.TextureAsset;
                    if (texture != null)
                    {
                        byte[]       textureData   = texture.GetContent();
                        MemoryStream textureStream = new MemoryStream(textureData);
                        image = Image.FromStream(textureStream);
                    }
                }
                if (image != null)
                {
                    assembly.Images.Add(materialName, image);
                    assembly.MatLinks.Add(materialName, materialName);
                }
                else
                {
                    Rbx2Source.Print("Missing Image for Material {0}?", materialName);
                }
            }

            return(assembly);
        }
Beispiel #30
0
        public Bitmap BakeTextureMap()
        {
            var bitmap = new Bitmap(canvas.Width, canvas.Height);

            layers.Sort();

            composed = 0;

            Rbx2Source.Print("Composing " + context + "...");
            Rbx2Source.IncrementStack();

            foreach (CompositData composit in layers)
            {
                var buffer    = Graphics.FromImage(bitmap);
                var drawFlags = composit.DrawFlags;
                var canvas    = composit.Rect;

                if (drawFlags.HasFlag(DrawFlags.Rect))
                {
                    if (drawFlags.HasFlag(DrawFlags.Color))
                    {
                        composit.UseBrush(brush => buffer.FillRectangle(brush, canvas));
                    }
                    else if (drawFlags.HasFlag(DrawFlags.Texture))
                    {
                        Bitmap image = composit.GetTextureBitmap();

                        if (composit.FlipMode > 0)
                        {
                            image.RotateFlip(composit.FlipMode);
                        }

                        buffer.DrawImage(image, canvas);
                    }
                }
                else if (drawFlags.HasFlag(DrawFlags.Guide))
                {
                    Mesh guide = composit.Guide;

                    for (int face = 0; face < guide.NumFaces; face++)
                    {
                        Vertex[] verts  = composit.GetGuideVerts(face);
                        Point    offset = canvas.Location;

                        Point[] poly = verts
                                       .Select(vert => vert.ToPoint(canvas, offset))
                                       .ToArray();

                        if (drawFlags.HasFlag(DrawFlags.Color))
                        {
                            composit.UseBrush(brush => buffer.FillPolygon(brush, poly));
                        }
                        else if (drawFlags.HasFlag(DrawFlags.Texture))
                        {
                            Bitmap    texture = composit.GetTextureBitmap();
                            Rectangle bbox    = GetBoundingBox(poly);

                            Point  origin    = bbox.Location;
                            Bitmap drawLayer = new Bitmap(bbox.Width, bbox.Height);

                            Point[] uv = verts
                                         .Select(vert => vert.ToUV(texture))
                                         .ToArray();

                            int origin_X = origin.X,
                                origin_Y = origin.Y;

                            for (int x = bbox.Left; x < bbox.Right; x++)
                            {
                                for (int y = bbox.Top; y < bbox.Bottom; y++)
                                {
                                    var pixel   = new Point(x, y);
                                    var bcPoint = new BarycentricPoint(pixel, poly);

                                    if (bcPoint.InBounds())
                                    {
                                        var   uvPixel = bcPoint.ToCartesian(uv);
                                        Color color   = texture.GetPixel(uvPixel.X, uvPixel.Y);
                                        drawLayer.SetPixel(x - origin_X, y - origin_Y, color);
                                    }
                                }
                            }

                            buffer.DrawImage(drawLayer, origin);
                            drawLayer.Dispose();
                        }
                    }
                }

                Rbx2Source.Print("{0}/{1} layers composed...", ++composed, layers.Count);

                if (layers.Count > 2)
                {
                    Rbx2Source.SetDebugImage(bitmap);
                }

                buffer.Dispose();
            }

            Rbx2Source.Print("Done!");
            Rbx2Source.DecrementStack();

            return(bitmap);
        }