Minecraft Schematic Importer

I’m working on this plugin that can import a minecraft .schematic file directly into your game from studio as blocks and I wanted to see what people thought of it. I’ll probably release it in the future if people are interested. I’ll also probably make a pixel art importer.

Example:

image

And Roblox (and my web API) parses it through and creates…


(a colored in example, I’ve yet to actually implement colors yet so it just imports it as a grey model and I did color this in manually after)

I wanted to create this so I could make a block-based game with an imported lobby since I can’t be bothered to pay my entire (lackthereof) salary to someone to build a map for me

Drawbacks:

  • Does not support massive files yet due to the fact it gets extremely laggy. I think the maximum my computer can handle is around 10,000 blocks. I’ll probably add like settings that can mesh them together to prevent extreme lag or combine multiple of the same blocks into 1 little row. If you have any suggestions don’t hesitate to mention them.

What do you guys think of this?

Source code:

22 Likes

SO. COOL. 10/10 A+ 100/100 stars

1 Like

Thanks! Any ideas to add or how you’d use it?

1 Like

Hmm. Maybe you could have it so that it can reference the Minecraft textures and apply them to the blocks, and also have the transparency somehow be transferred?

I would use it to create simpler builds, perhaps as an easy way to prototype builds, that’d actually be really useful.

This is very creative and amazing! I wondered if it imported lanterns with the LightPoint’s or not?

I haven’t dealt with fine details like that yet. It currently only deals with block types and positioning, yet to implement colors and materials etc.

Its amazing, its rare to see such amazing creations. Hopefully it can be implemented with textures, transparency etc.

I’m not sure if I’ll be able to get away with textures because copyright but I’ll try my best to replicate colors, transparency & materials.

2 Likes

outstanding!! never would of thought of this! great job!

2 Likes

Here’s the source code for anyone curious:
Run this in your command bar, it will prompt you to upload your schematic file.

  • Your computer will explode if you try to import a big boi file, so don’t do that please! :slight_smile:
local plugin = plugin or PluginManager():CreatePlugin()
local studioService = game:GetService("StudioService");
local httpService = game:GetService("HttpService");
local runService = game:GetService("RunService");
local heartbeat = runService.Heartbeat;
local url = "https://minecraft-schematic.glitch.me/"

function enc(data)
local alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -- You will need this for encoding/decoding
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return alphabet:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end

local decode = function(encoded)
local success,response = pcall(function()
local apiUrl = (url .. "/decode");
return httpService:PostAsync(apiUrl,encoded,Enum.HttpContentType.TextPlain);
end)
if(success and response) then
return(httpService:JSONDecode(response));
else
error("Something went wrong.",response);
end
end
local destination = workspace:FindFirstChild("imported");
if(not destination) then
destination = Instance.new("Folder",workspace);
end
destination.Name = "imported";

function enc(data)
local alphabet='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' -- You will need this for encoding/decoding
return ((data:gsub('.', function(x)
local r,b='',x:byte()
for i=8,1,-1 do r=r..(b%2^i-b%2^(i-1)>0 and '1' or '0') end
return r;
end)..'0000'):gsub('%d%d%d?%d?%d?%d?', function(x)
if (#x < 6) then return '' end
local c=0
for i=1,6 do c=c+(x:sub(i,i)=='1' and 2^(6-i) or 0) end
return alphabet:sub(c+1,c+1)
end)..({ '', '==', '=' })[#data%3+1])
end

local studioService = game:GetService("StudioService");
local success,imported = pcall(function()
return studioService:PromptImportFile({"schematic","schem"})
end)

local binary = imported:GetBinaryContents();
local encodedBinary = enc(binary);
local s = Instance.new("Script",workspace);
s.Source = encodedBinary;

local h = function(a,f)
return Vector3.new(a[1]*f,a[2]*f,a[3]*f)
end

local directions = {
["base"] = {
["bottom"] = {
["east"] = Vector3.new(0, -90, 0),
["south"] = Vector3.new(0,-180,0);
["west"] = Vector3.new(0, 90, 0),
["north"] = Vector3.new(0, 0, 0),
["up"] = Vector3.new(0,0,0),
["down"] = Vector3.new(0,0,0)
},
["top"] = {
["east"] = Vector3.new(90, -90, 0),
["south"] = Vector3.new(90, 180, 0);
["west"] = Vector3.new(90, 90, 0),
["north"] = Vector3.new(90, 0, 0),
["up"] = Vector3.new(0,0,0),
["down"] = Vector3.new(0,0,0)
}
}
}

local getFrom = function(block)
if(block.name:lower():find("stair")) then
return game:GetService("ReplicatedStorage"):WaitForChild("stairs"):Clone();
else
return Instance.new("Part");
end
end

if(imported and success) then
local file = imported;
local binary = file:GetBinaryContents();
local encodedBinary = enc(binary);
local stop = false;
local s;
s = workspace.AttributeChanged:Connect(function()
stop = true;
end)
print("decoding")
local count = 0;
local decoded = decode(encodedBinary);
local f = 4;
for _,block in pairs(decoded.blocks) do
count += 1;
local raw = getFrom(block);
raw.Size = Vector3.new(1 * f,1 * f ,1 * f);
raw.Position = h(block.position,f);
raw.Material = Enum.Material.SmoothPlastic;
raw.Anchored = true;
local category = destination:FindFirstChild([block.name](http://block.name/)) or Instance.new("Folder");
category.Parent = destination;
category.Name = [block.name](http://block.name/);
raw.Parent = category;
if(block.properties.facing) then
raw.Orientation = directions[raw:GetAttribute("base") or "base"][block.properties.half or "bottom"][block.properties.facing];
raw:SetAttribute("properties",httpService:JSONEncode(block.properties));
end
if(count >= (300)) then
count = 0;
wait();
end
if(stop) then
break;
end
end
print("done")
pcall(function()
s:Disconnect();
end)
else
error("Something went wrong whilst importing your file.");
end

And the server side of it is operated on glitch.me.
See here

View code in glitch: (Glitch :・゚✧)

const path = require("path");
const zlib = require("zlib");
const { Schematic } = require("prismarine-schematic");
const Block = require("prismarine-block");
const fastify = require("fastify")({
logger: false
});

[fastify.post](http://fastify.post/)("/decode", async function(request,reply) {
try {
var schematicBuffer = Buffer.from(request.body, "base64");
var schematic = await Schematic.read(schematicBuffer);
var response = { blocks: {}, failed: false, count: 0, "states": schematic.palette};
var count = 0;
var rawCount = 0;
var total = schematic.blocks.length;
schematic.forEach(function(block, position) {
var pos = [position.x, position.y, position.z];
var key = count + 1;
var state = schematic.getBlockStateId(position);
if ([block.name](http://block.name/) !== "air") {
rawCount += 1;
response.blocks[parseInt(key)] = {
name: [block.name](http://block.name/),
position: pos,
state: state,
properties: block.getProperties()
};
}
count += 1;
if (count >= total) {
response.count = rawCount;
reply.send(response);
}
});
} catch (e) {
console.log(e)
reply.code(400).send({ failed: true, error: e });
}
});

fastify.listen(process.env.PORT, function(err, address) {
if (err) {
fastify.log.error(err);
process.exit(1);
}
console.log(`Your app is listening on ${address}`);
[fastify.log.info](http://fastify.log.info/)(`server listening on ${address}`);
});

1 Like

Does this still work? i could just be doing it wrong but the code just errors for me. edit: i ended up using the base of your code and rewriting alot of parts and now it works perfectly thanks for sharing this

1 Like

this needs to have more attention. impressive.