0,,88U0]HD4qqm4qή 02TvͫgE#2Tv2Tv zwwwqwzwwzwzzwwzwwwwwwwqwwwUUUUUUUUUUUUUUUU[UUUUUUUUUUUU[U[U[UU[UUUUU[UUUUU[UUUUUU5U5U55s353DC9DI39IDDUUUUU[U[S;5993sI9IDII4DDD3CIt3DIDI9DID9IDDDI4IG3DDI9DtI9IDII4DDzzzzwwwwzwwwwwzwwwwzwwwwwzwqwwwwwqpwwwq wpww wIIIIDDDDIDDDDDDDDIIIDDDD̪zzwwzzzwwwzzwwwwzwqwwwwqzzw[[[[UUUUUUUUU[UUUUUUUUUUUUUUU[U[UU[UUUUUUUUUU[U[UUUUUUII9D9DIDIDI9IIDC99DDIDICDGC9D94ID9DDD9II9D9DIDIDI9IIDC99DDIDICDGC9D94ID9DDD9zwwwwwwwzzzwzwwwzzzwzwww wqwpwqwpwzpzpzww qwwqwwIIIIIDDDDIIDDDDIIDDDDIIIIIDDDDD4D4DDD4DCD43333DD4DDDDDDCDD3333CDDDDCDDDDDC3333DCD4DDD4CDC43333CC9C4CC4C44DC4DDDDDIDDCI4C99DDD9C9DC9C4C4CC9DCC94DCpp1C11A11C1313333343314C1333CC1A31ACA1CA1C1131131DCD3DDDIDIIC4DDIDDDII9IIDIII9II313CDDDA333CCDDACDDAC43AC4DAC4D133DDD43334DD4DD443C44DC4DC44UU-R]]]]RR-UU]%U-]"]%-URUURUUUR--]-"]%--DCD4DD44D4D43333D4DD4DDDDDDC3333DC4DDDDDD4DD3333D4D4DDD44DD43333C94CCCCCCCCCCDDCC9D3D4D449DC49CC9C9C9DD49I9DCD4DDpppC1C1C111C111CAA1C11331133331C11CA1CA13A3C431333IIIDDDDDCDCIIIIDIIIII9DDD9IDD3CCC4DCC4DCC43ACDDACDDA333ADDD3131DC44DC443C44DD44DD4333DDD4331U]%U%--UU]R]-R]-]]%RURU]R]]R-]R-R]%U]Rۻۻ]۵ݽ۽۽ս۵յ]ջ[]U[]ۻۻۻ]]]U[]]"""--""-"""----""R--"""R"%"-%""-"---R""ݓI9̓Ó9CDD4I99949C4D4̓9<94C4344999399C433̓9̓3LDDLLLDD̜<33C9<9D3Lmax_v) and max_v or val end local function min_abs(a,b) return (abs(a) < abs(b)) and a or b end local function max_abs(a,b) return (abs(a) > abs(b)) and a or b end local function sign(val) return (val > 0) and 1 or (val < 0) and -1 or 0 end local function sub_abs(a,b) return (a > 0) and max(a-b,0) or (a<0) and min(a+b,0) or 0 end local function mean2(val_a,val_b) return (val_a + val_b)*0.5 end local function mean(...)local l,sum={...},0 for i=1,#l do sum=sum+l[i] end return sum/#l end local function FtoStep(val,step) return F(val/step)*step end local function median(tbl) if #tbl < 1 then return nil end local tbl2 = table.pack(table.unpack(tbl)) table.sort(tbl2) return tbl2[#tbl2//2 + 1] end -- Random local function Rf(min_v,max_v) if not max_v then return Rf(-min_v,min_v) end return math.random()*(max_v-min_v)+min_v end local function random(...)local l = {...}return l[R(1,#l)]end local function randomFrom(l)return l[R(1,#l)]end -- Logic local function lerp(val_a,val_b,coef) return val_a*(1-coef) + val_b * coef end local function map_val(val,a_min,a_max,b_min,b_max) return (val-a_min)/(a_max-a_min)*(b_max-b_min) + b_min end local function smoothstep(val_a,val_b,x)x=clamp((x-val_a)/(val_b-val_a),0,1)return x*x*(3-2*x)end local function in_range(val,min_val,max_val) return val >= min_val and val <= max_val end local function print_mid(str,x,y,...) print(str,x-print(str,240,0)//2,y,...) end local function select(n, ...) local list = { ... }return list[max(1, min(n, #list))] end local function isInTable(tbl, val) for _, curVal in pairs(tbl) do if curVal == val then return true end end return false end ---- settings ---- local render_distance = 2 local chunk_update_cooldown = 3 -- world size in chunks (1 chunk = 8x8x8 blocks) local w_size1 = 8 -- width (x) local w_size2 = 4 -- height (y) local w_size3 = 8 -- depth (z) ---- Game data ---- --[[ instruments: 0 - hand 1 - pickaxe 2 - axe 3 - shovel 4 - shears 5 - bucket 6 - flint and steel 7 - sword 8 - helmet 9 - chestplate 10 - leggins 11 - boots level: 0 - hand 1 - wood 2 - stone / gold 3 - iron 4 - diamond ]] local blocks_data = { [1 ] = {name="Stone Block" , break_t = 270, texture={0}, drop = 4, instrument = 1, level = 1}, [2 ] = {name="Grass Block" , break_t = 60 , texture={1,2,3}, drop = 3, instrument = 3}, [3 ] = {name="Dirt Block" , break_t = 40 , texture={3}, instrument = 3}, [4 ] = {name="Cobblestone" , break_t = 120, texture={4}, instrument = 1, level = 1}, [5 ] = {name="bedrock" , break_t = math.huge, texture={5}}, [6 ] = {name="Oak planks" , break_t = 120, texture={6}, instrument = 2}, [7 ] = {name="Birch planks" , break_t = 120, texture={7}, instrument = 2}, [8 ] = {name="Spruce planks" , break_t = 120, texture={8}, instrument = 2}, [9 ] = {name="Oak log" , break_t = 120, texture={12, 9}, instrument = 2}, [10] = {name="Birch log" , break_t = 120, texture={13,10}, instrument = 2}, [11] = {name="Spruce log" , break_t = 120, texture={14,11}, instrument = 2}, [12] = {name="Oak leaves" , break_t = 10 , texture={15}, transp=true, drop = 0, instrument = 4}, [13] = {name="Birch leaves" , break_t = 10 , texture={16}, transp=true, drop = 0, instrument = 4}, [14] = {name="Spruce leaves" , break_t = 10 , texture={17}, transp=true, drop = 0, instrument = 4}, [15] = {name="Crafting table", break_t = 120, texture={19,18,20}, instrument = 2}, [16] = {name="Chest" , break_t = 120, texture={20,21,20,22}, instrument = 2}, [17] = {name="Furnace" , break_t = 120, texture={23,24,23,25}, instrument = 1, level = 1}, [18] = {name="Coal ore" , break_t = 270, texture={26}, instrument = 1, level = 1}, [19] = {name="Iron ore" , break_t = 270, texture={27}, instrument = 1, level = 2}, [20] = {name="Gold ore" , break_t = 270, texture={28}, instrument = 1, level = 3}, [21] = {name="Diamond ore" , break_t = 270, texture={29,bg=-1}, instrument = 1, level = 3}, [22] = {name="Grass" , break_t = 10 , texture={30}, grass=true, drop = 0, instrument = 4}, [23] = {name="Rose" , break_t = 10 , texture={31}, grass=true, instrument = 4}, [24] = {name="Dandelion" , break_t = 10 , texture={32}, grass=true, instrument = 4}, [25] = {name="Gravel" , break_t = 60 , texture={33}, instrument = 3}, [26] = {name="Sand" , break_t = 60 , texture={34}, instrument = 3}, [27] = {name="Cactus" , break_t = 30 , texture={36,35}, instrument = 4}, [28] = {name="Glass" , break_t = 60 , texture={37,bg=1}, transp=true ,drop = 0}, [29] = {name="Water" , break_t = 60 , texture={38,bg=1}, transp=true, instrument = 5}, [30] = {name="Lava" , break_t = 60 , texture={39,bg=1}, transp=true, instrument = 5}, [31] = {name="Obsidian" , break_t = 900, texture={40,bg=-1}, instrument = 1, level = 4}, [32] = {name="Netherack" , break_t = 120, texture={41}, instrument = 1, level = 1}, [33] = {name="Soul sand" , break_t = 60 , texture={42}, instrument = 3}, [34] = {name="Fire" , break_t = 10 , texture={43}, grass=true, drop = 0}, [35] = {name="Nether portal" , break_t = math.huge, texture={44,bg=-1}, transp=true}, [36] = {name="Portal frame" , break_t = math.huge, texture={46,45,50,bg=-1}}, [37] = {name="Portal frame 2", break_t = math.huge, texture={47,45,50,bg=-1}}, [38] = {name="End portal" , break_t = math.huge, texture={48}}, [39] = {name="Stone bricks" , break_t = 120, texture={49}, instrument = 1, level = 1}, [40] = {name="End stone" , break_t = 120, texture={50}, instrument = 1, level = 1}, [41] = {name="Iron bars" , break_t = 180, texture={51}, transp=true, instrument = 1}, } local items_data = { [64 ] = {name="stick" ,texture=64}, [65 ] = {name="Iron ingot" ,texture=65, palmap="012175678aabcdaf"}, [66 ] = {name="Gold ingot" ,texture=65, palmap="0124456789abcdef"}, [67 ] = {name="Coal" ,texture=66}, [68 ] = {name="Flint" ,texture=67}, [69 ] = {name="Diamond" ,texture=68}, [70 ] = {name="Wooden pickaxe" ,texture=72, palmap="0123456739abc4e9", instrument = 1, level = 1}, [71 ] = {name="Stone pickaxe" ,texture=72, palmap="0123456719abc7ea", instrument = 1, level = 2}, [72 ] = {name="iron pickaxe" ,texture=72, palmap="0123456779abcaef", instrument = 1, level = 3}, [73 ] = {name="Gold pickaxe" ,texture=72, palmap="0123456799abceef", instrument = 1, level = 2}, [74 ] = {name="Diamond pickaxe" ,texture=72, instrument = 1, level = 4}, [75 ] = {name="Wooden axe" ,texture=73, palmap="0123456739abc4e9", instrument = 2, level = 1}, [76 ] = {name="Stone axe" ,texture=73, palmap="0123456719abc7ea", instrument = 2, level = 2}, [77 ] = {name="Iron axe" ,texture=73, palmap="0123456779abcaef", instrument = 2, level = 3}, [78 ] = {name="Gold axe" ,texture=73, palmap="0123456799abceef", instrument = 2, level = 2}, [79 ] = {name="Diamond axe" ,texture=73, instrument = 2, level = 4}, [80 ] = {name="Wooden shovel" ,texture=74, palmap="0123456739abc4e9", instrument = 3, level = 1}, [81 ] = {name="Stone shovel" ,texture=74, palmap="0123456719abc7ea", instrument = 3, level = 2}, [82 ] = {name="Iron shovel" ,texture=74, palmap="0123456779abcaef", instrument = 3, level = 3}, [83 ] = {name="Gold shovel" ,texture=74, palmap="0123456799abceef", instrument = 3, level = 2}, [84 ] = {name="Diamond shovel" ,texture=74, instrument = 3, level = 4}, [85 ] = {name="Wooden sword" ,texture=75, palmap="0123456739abc4e9", instrument = 4, level = 1}, [86 ] = {name="Stone sword" ,texture=75, palmap="0123456719abc7ea", instrument = 4, level = 2}, [87 ] = {name="Iron sword" ,texture=75, palmap="0123456779abcaef", instrument = 4, level = 3}, [88 ] = {name="Gold sword" ,texture=75, palmap="0123456799abceef", instrument = 4, level = 2}, [89 ] = {name="Diamond sword" ,texture=75, instrument = 4, level = 4}, [90 ] = {name="iron helmet" ,texture=76, palmap="0123456779abcaef"}, [91 ] = {name="gold helmet" ,texture=76, palmap="0123456799abceef"}, [92 ] = {name="diamond helmet" ,texture=76}, [93 ] = {name="iron chestplate" ,texture=77, palmap="0123456779abcaef"}, [94 ] = {name="gold chestplate" ,texture=77, palmap="0123456799abceef"}, [95 ] = {name="diamond chestplate",texture=77}, [96 ] = {name="iron leggins" ,texture=78, palmap="0123456779abcaef"}, [97 ] = {name="gold leggins" ,texture=78, palmap="0123456799abceef"}, [98 ] = {name="diamond leggins" ,texture=78}, [99 ] = {name="iron boots" ,texture=79, palmap="0123456779abcaef"}, [100] = {name="gold boots" ,texture=79, palmap="0123456799abceef"}, [101] = {name="diamond boots" ,texture=79}, [102] = {name="Flint and steel" ,texture=80, instrument = 6}, [103] = {name="Shears" ,texture=81, instrument = 5}, [104] = {name="Ender pearl" ,texture=82, bg=7}, [105] = {name="Eye of the ender" ,texture=83, bg=7}, [106] = {name="Blaze rog" ,texture=84}, [107] = {name="Blaze powder" ,texture=85}, [108] = {name="String" ,texture=86}, [109] = {name="Feather" ,texture=87}, [110] = {name="Bow" ,texture=88}, [111] = {name="Arrow" ,texture=89}, [112] = {name="Bucket" ,texture=90}, [113] = {name="Bucket of water" ,texture=91}, [114] = {name="Bucket of lava" ,texture=92}, [115] = {name="Raw meat" ,texture=93}, [116] = {name="Cooked meat" ,texture=94}, [117] = {name="Apple" ,texture=95}, [118] = {name="Golden apple" ,texture=95, palmap="032945e789abfdef"}, } local instrument_speed = { [1] = 1.5, [2] = 3.0, [3] = 5.0, [4] = 8.5, } local crafts = { { -- Oak planks 9, 0, 0, 0, 0, 0, 0, 0, 0, result={id = 6, count = 4} }, { -- Birch planks 10, 0, 0, 0, 0, 0, 0, 0, 0, result={id = 7, count = 4} }, { -- Spruce planks 11, 0, 0, 0, 0, 0, 0, 0, 0, result={id = 8, count = 4} }, { -- Crafting table {6, 7, 8}, {6, 7, 8}, 0, {6, 7, 8}, {6, 7, 8}, 0, 0, 0, 0, result={id = 15, count = 1} }, { -- Sticks {6, 7, 8}, 0, 0, {6, 7, 8}, 0, 0, 0, 0, 0, result={id = 64, count = 4} }, { -- Stone bricks 1, 1, 0, 1, 1, 0, 0, 0, 0, result={id = 39, count = 4} }, -- Instruments { {6, 7, 8},{6, 7, 8},{6, 7, 8},0,64,0,0,64,0, result={id = 70, count = 1} }, { {6, 7, 8},{6, 7, 8},0,{6, 7, 8},64,0,0,64,0, result={id = 75, count = 1} }, { {6, 7, 8},{6, 7, 8},0,64,{6, 7, 8},0,64,0,0, result={id = 75, count = 1} }, { {6, 7, 8},0,0,64,0,0,64,0,0, result={id = 80, count = 1} }, { {6, 7, 8},0,0,{6, 7, 8},0,0,64,0,0, result={id = 85, count = 1} }, -- { 4,4,4,0,64,0,0,64,0, result={id = 71, count = 1} }, { 4,4,0,4,64,0,0,64,0, result={id = 76, count = 1} }, { 4,4,0,64,4,0,64,0,0, result={id = 76, count = 1} }, { 4,0,0,64,0,0,64,0,0, result={id = 81, count = 1} }, { 4,0,0,4,0,0,64,0,0, result={id = 86, count = 1} }, -- { 65,65,65,0,64,0,0,64,0, result={id = 72, count = 1} }, { 65,65,0,65,64,0,0,64,0, result={id = 77, count = 1} }, { 65,65,0,64,65,0,64,0,0, result={id = 77, count = 1} }, { 65,0,0,64,0,0,64,0,0, result={id = 82, count = 1} }, { 65,0,0,65,0,0,64,0,0, result={id = 87, count = 1} }, -- { 66,66,66,0,64,0,0,64,0, result={id = 73, count = 1} }, { 66,66,0,66,64,0,0,64,0, result={id = 78, count = 1} }, { 66,66,0,64,66,0,64,0,0, result={id = 78, count = 1} }, { 66,0,0,64,0,0,64,0,0, result={id = 83, count = 1} }, { 66,0,0,66,0,0,64,0,0, result={id = 88, count = 1} }, -- { 69,69,69,0,64,0,0,64,0, result={id = 74, count = 1} }, { 69,69,0,69,64,0,0,64,0, result={id = 79, count = 1} }, { 69,69,0,64,69,0,64,0,0, result={id = 79, count = 1} }, { 69,0,0,64,0,0,64,0,0, result={id = 84, count = 1} }, { 69,0,0,69,0,0,64,0,0, result={id = 89, count = 1} }, } ---- UV data local breakingUV = {} -- updating UVs local function generateUV(up, side, down, front, bg, palmap) local up_x, up_y = (up % 8) * 16, (up // 8) * 16 local front_x, front_y = (front % 8) * 16, (front // 8) * 16 local down_x, down_y = (down % 8) * 16, (down // 8) * 16 local side_x, side_y = (side % 8) * 16, (side // 8) * 16 local uv = { {up_x, up_y, up_x + 16, up_y, up_x + 16, up_y + 16, up_x, up_y + 16}, {down_x, down_y, down_x + 16, down_y, down_x + 16, down_y + 16, down_x, down_y + 16}, {side_x, side_y, side_x + 16, side_y, side_x + 16, side_y + 16, side_x, side_y + 16}, {side_x, side_y, side_x + 16, side_y, side_x + 16, side_y + 16, side_x, side_y + 16}, {front_x, front_y, front_x + 16, front_y, front_x + 16, front_y + 16, front_x, front_y + 16}, {side_x, side_y, side_x + 16, side_y, side_x + 16, side_y + 16, side_x, side_y + 16}, bg = bg or 13, palmap = palmap } return uv end for _, bl in ipairs(blocks_data) do local up = bl.texture[1] local side = bl.texture[2] or up local down = bl.texture[3] or up local front = bl.texture[4] or side bl.uv = generateUV(up, side, down, front, bl.texture.bg, bl.palmap) end for i = 0, 9 do local spr_id = 54 + i breakingUV[i] = generateUV(spr_id, spr_id, spr_id, spr_id) end local function isBlockTransp(id, cur) return (id == 0) or (blocks_data[id].transp == true and (cur ~= id)) or (blocks_data[id].grass == true) end local function isCollBlock(id) return (id > 0) and not (blocks_data[id].grass) end ---- mouse ----- local mx, my local mtick = 0 local cl1, cl2, cl3 local clp1, clp2, clp3 local mt1, mt2, mt3 local whl, c_id local function mouseUpdate() mx, my, cl1, cl2, cl3, _, whl = mouse() if cl1 then mt1 = mt1 + 1 else mt1 = 0 end if cl2 then mt2 = mt2 + 1 else mt2 = 0 end if cl3 then mt3 = mt3 + 1 else mt3 = 0 end clp1 = (mt1 == 1) clp2 = (mt2 == 1) clp3 = (mt3 == 1) mtick = max(mtick - 1, 0) if mtick > 0 then mx, my = 0, 0 end end ---- debug library ---- local debug = { frameStart = 0, prevTime = 0, rate = {}, frame = {}, -- median data medRate = {}, medFrame = 0, medFPS = 0, compileRate = {}, -- additional data data = {}, } function debug.start() debug.frameStart = time() debug.prevTime = time() debug.data = {} end function debug.addtime(name) local ln = time() - debug.prevTime if not debug.rate[name] then debug.rate[name] = {} end if #debug.rate[name] < 60 then table.insert(debug.rate[name], ln) else for i = 2, 60 do debug.rate[name][i - 1] = debug.rate[name][i] end debug.rate[name][60] = ln end debug.prevTime = time() end function debug.finish() -- framerate update local framerate = time() - debug.frameStart if #debug.frame < 60 then table.insert(debug.frame, framerate) else for i = 2, 60 do debug.frame[i - 1] = debug.frame[i] end debug.frame[60] = framerate end -- Calculating median local tbl = {} for i = 1, #debug.frame do tbl[i] = debug.frame[i] end table.sort(tbl) debug.medFrame = tbl[#tbl // 2 + 1] debug.medFPS = 1000 / debug.medFrame -- Median rate debug.medRate = {} for name, data in pairs(debug.rate) do tbl = {} for i = 1, #data do tbl[i] = data[i] end table.sort(tbl) local med = tbl[#tbl // 2 + 1] table.insert(debug.medRate, {name = name, val = med}) end table.sort(debug.medRate, function(a, b) return a.val < b.val end) table.insert(debug.medRate, {name = "total", val = debug.medFrame}) -- Compiling rate debug.medComp = median(debug.compileRate) end function debug.tracetable(tbl) trace("{", 12) for key, val in pairs(tbl) do trace(stf("[%s] = %s,", key, val), 12) end trace("}", 12) trace("") end ---- Vector library ---- local vecMt = {} vecMt.__index = vecMt do function vecMt.__add(a,b) if type(a) == "number" then a = vec3(a) end if type(b) == "number" then b = vec3(b) end return vec3(a.x + b.x, a.y + b.y, a.z + b.z) end function vecMt.__sub(a,b) if type(a) == "number" then a = vec3(a) end if type(b) == "number" then b = vec3(b) end return vec3(a.x - b.x, a.y - b.y, a.z - b.z) end function vecMt.__mul(a,b) if type(a) == "number" then a = vec3(a) end if type(b) == "number" then b = vec3(b) end -- We check for the presence of an element at index 1 -- because this means that it is a matrix if a[1] then a, b = b, a end -- multiplying by the matrix if b[1] then local x = b[1][1]*a.x + b[1][2]*a.y + b[1][3]*a.z + b[1][4] local y = b[2][1]*a.x + b[2][2]*a.y + b[2][3]*a.z + b[2][4] local z = b[3][1]*a.x + b[3][2]*a.y + b[3][3]*a.z + b[3][4] local w = b[4][1]*a.x + b[4][2]*a.y + b[4][3]*a.z + b[4][4] return vec3(x/w, y/w, z/w) else return vec3(a.x * b.x, a.y * b.y, a.z * b.z) end end function vecMt:rotateByMat(mt) local x = mt[1][1]*self.x + mt[1][2]*self.y + mt[1][3]*self.z local y = mt[2][1]*self.x + mt[2][2]*self.y + mt[2][3]*self.z local z = mt[3][1]*self.x + mt[3][2]*self.y + mt[3][3]*self.z return vec3(x, y, z) end function vecMt.__div(a,b) if type(a) == "number" then a = vec3(a) end if type(b) == "number" then b = vec3(b) end return vec3(a.x / b.x, a.y / b.y, a.z / b.z) end function vecMt.__mod(a,b) if type(a) == "number" then a = vec3(a) end if type(b) == "number" then b = vec3(b) end return vec3(a.x % b.x, a.y % b.y, a.z % b.z) end function vecMt.__idiv(a,b) if type(a) == "number" then a = vec3(a) end if type(b) == "number" then b = vec3(b) end return vec3(a.x // b.x, a.y // b.y, a.z // b.z) end function vecMt.__tostring(self) return stf("[%.1f;%.1f;%.1f]",self.x,self.y,self.z) end function vecMt.__concat(a,b) return tostring(a)..tostring(b) end function vecMt:length() return math.sqrt(self.x*self.x + self.y*self.y + self.z*self.z) end function vecMt:normalize() local len = math.sqrt(self.x*self.x + self.y*self.y + self.z*self.z) if len > 0 then return vec3(self.x / len, self.y / len, self.z / len) else return vec3() end end function vecMt:rotate_xy(angle) local tsin,tcos = sin(-angle),cos(-angle) return vec3( self.x*tcos - self.y*tsin, self.x*tsin + self.y*tcos, self.z ) end function vecMt:rotate_xz(angle) local tsin,tcos = sin(-angle),cos(-angle) return vec3( self.x*tcos - self.z*tsin, self.y, self.x*tsin + self.z*tcos ) end function vecMt:rotate_yz(angle) local tsin,tcos = sin(angle),cos(angle) return vec3( self.x, self.y*tcos - self.z*tsin, self.y*tsin + self.z*tcos ) end function vecMt:xyz() return self.x, self.y, self.z end end function vec3(vx,vy,vz) vx = tonumber(vx or 0) vy = tonumber(vy or vx or 0) vz = tonumber(vz or vx or 0) local vector = {x = vx, y = vy, z = vz} return setmetatable(vector,vecMt) end local function dot(v1,v2) return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z end local function cross(v1,v2) local x = v1.y * v2.z - v1.z * v2.y local y = v1.z * v2.x - v1.x * v2.z local z = v1.x * v2.y - v1.y * v2.x return vec3(x, y, z) end local function vecToEuler(front) front = front:normalize() local pitch = math.asin(front.y) local yaw = -math.atan2(front.x, front.z) return pitch, yaw end local function EulertoVec(pitch, yaw) local front = vec3(0, 0, 1) return front:rotate_yz(-pitch):rotate_xz(-yaw) end local dirs = { ["-x"] = vec3(-1, 0, 0), ["+x"] = vec3( 1, 0, 0), ["-y"] = vec3( 0,-1, 0), ["+y"] = vec3( 0, 1, 0), ["-z"] = vec3( 0, 0,-1), ["+z"] = vec3( 0, 0, 1), } ---- Matrix library ---- local matMt = {} -- matrix metatable function matMt.__mul(m1, m2) -- This code may seem quite terrible (it is) -- But its main goal is to get the maximum -- performance by reducing the quantity -- Requests to tables, as well as no cycles. -- In fact, this is a standard algorithm -- for multiplying matrices. local a1,a2,a3,a4 = m1[1],m1[2],m1[3],m1[4] local b1,b2,b3,b4 = m2[1],m2[2],m2[3],m2[4] local a11,a12,a13,a14 = a1[1],a1[2],a1[3],a1[4] local a21,a22,a23,a24 = a2[1],a2[2],a2[3],a2[4] local a31,a32,a33,a34 = a3[1],a3[2],a3[3],a3[4] local a41,a42,a43,a44 = a4[1],a4[2],a4[3],a4[4] local b11,b12,b13,b14 = b1[1],b1[2],b1[3],b1[4] local b21,b22,b23,b24 = b2[1],b2[2],b2[3],b2[4] local b31,b32,b33,b34 = b3[1],b3[2],b3[3],b3[4] local b41,b42,b43,b44 = b4[1],b4[2],b4[3],b4[4] local result = { {a11*b11+a12*b21+a13*b31+a14*b41,a11*b12+a12*b22+a13*b32+a14*b42,a11*b13+a12*b23+a13*b33+a14*b43,a11*b14+a12*b24+a13*b34+a14*b44}, {a21*b11+a22*b21+a23*b31+a24*b41,a21*b12+a22*b22+a23*b32+a24*b42,a21*b13+a22*b23+a23*b33+a24*b43,a21*b14+a22*b24+a23*b34+a24*b44}, {a31*b11+a32*b21+a33*b31+a34*b41,a31*b12+a32*b22+a33*b32+a34*b42,a31*b13+a32*b23+a33*b33+a34*b43,a31*b14+a32*b24+a33*b34+a34*b44}, {a41*b11+a42*b21+a43*b31+a44*b41,a41*b12+a42*b22+a43*b32+a44*b42,a41*b13+a42*b23+a43*b33+a44*b43,a41*b14+a42*b24+a43*b34+a44*b44} } return matrix.new(result) end -- I'm not sure if anything other -- than matrix multiplication is needed, -- but if so, let me know! matrix = { -- Creating a new matrix new = function(mat) mat = mat or { {1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}, } setmetatable(mat, matMt) return mat end, -- Rotation matrices along each axis rotationX = function(angle) local cosA = cos(angle) local sinA = sin(angle) return matrix.new({ {1, 0, 0, 0}, {0, cosA,-sinA, 0}, {0, sinA, cosA, 0}, {0, 0, 0, 1} }) end, rotationY = function(angle) local cosA = cos(angle) local sinA = sin(angle) return matrix.new({ {cosA, 0, sinA, 0}, {0, 1, 0, 0}, {-sinA, 0, cosA, 0}, {0, 0, 0, 1} }) end, rotationZ = function(angle) local cosA = cos(angle) local sinA = sin(angle) return matrix.new({ {cosA,-sinA, 0, 0}, {sinA, cosA, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1} }) end, -- Translation matrix translation = function(posX, posY, posZ) if type(posX) ~= "number" then posX, posY, posZ = posX.x, posX.y, posX.z end return matrix.new({ {1, 0, 0, posX}, {0, 1, 0, posY}, {0, 0, 1, posZ}, {0, 0, 0, 1} }) end, -- Scaling matrix scale = function(scaleX, scaleY, scaleZ) if type(scaleX) ~= "number" then scaleX, scaleY, scaleZ = scaleX.x, scaleX.y, scaleX.z elseif not scaleY then scaleY, scaleZ = scaleX, scaleX end return matrix.new({ {scaleX,0,0,0}, {0,scaleY,0,0}, {0,0,scaleZ,0}, {0,0,0,1}, }) end, } ---- Pallete stuff ---- local pal = "0400002c2c381c380049381ca45d1c488908ea44347171818d6df2eb8534a59daa71ce14ceae89a1d2fff7e2a5ffffff" local function respal() for i=1,#pal,2 do poke(0x3FC0+i//6*3+i//2%3,tonumber(pal:sub(i,i+1),16)) end end local function updpal(r,g,b) for i=0,47,3 do poke(0x03FC0+i,peek(0x03FC0+i)*r) --RLUE poke(0x03FC1+i,peek(0x03FC1+i)*g) --BREEN poke(0x03FC2+i,peek(0x03FC2+i)*b) --GED end end local function darkpal(c) for i=0,47 do --RGB poke(0x03FC0+i,peek(0x03FC0+i)*c) end end ---- Chunk engine ---- local getblock, setblock local updateQueue = {} local world = {} local function newChunk(pos_x, pos_y, pos_z) -- information about blocks in a chunk local blocks = "" for i = 0, 511 do blocks = blocks .. string.char(0) end -- Chuck metadata local chunk = { blocks = blocks, render = nil, x = pos_x, y = pos_y, z = pos_z, } return chunk end local function compileChunk(chunk) local start = time() local is_empty = true local code = {} local v_code = {} local f_code = {} -- Init variables table.insert(code, [[ return function(plr_x, plr_y, plr_z, pitch, yaw) local ttri=ttri local txsin=math.sin(pitch) local txcos=math.cos(pitch) local tysin=math.sin(yaw) local tycos=math.cos(yaw) local a1, b1, c1, c2, a3, b3, c3, x1, y1, z1 ]]) -- Used vertices local v_used = {} -- Some metadata local blocks = chunk.blocks local tri_v = { {4, 8, 7, 3}, -- up {1, 5, 6, 2}, -- down {4, 3, 1, 2}, -- left {7, 8, 6, 5}, -- right {3, 7, 5, 1}, -- front {8, 4, 2, 6} -- back } local grass_v = { {3, 8, 6, 1}, {7, 4, 2, 5} } -- chunk coordinates local cx, cy, cz = chunk.x, chunk.y, chunk.z local curPalMap = "0123456789abcdef" -- Faces for x=0,7 do for y=0,7 do for z=0,7 do local adr = 1 + x + y * 8 + z * 64 local block_id = string.byte(chunk.blocks, adr) if block_id > 0 then is_empty = false local block_v = { x .."_"..y .."_"..z , x .."_"..y .."_"..z+1, x .."_"..y+1 .."_"..z , x .."_"..y+1 .."_"..z+1, x+1 .."_"..y .."_"..z , x+1 .."_"..y .."_"..z+1, x+1 .."_"..y+1 .."_"..z , x+1 .."_"..y+1 .."_"..z+1, } local uv = blocks_data[block_id].uv local palMap = uv.palmap or "0123456789abcdef" ---- Grass ----- if blocks_data[block_id].grass then if palMap ~= curPalMap then for i = 0, 7 do table.insert(f_code, "poke(".. 0x03FF0+i ..","..tonumber(palMap:sub(i*2+1,i*2+2):reverse(),16)..")") end curPalMap = palMap end for i = 1, 2 do local i1 = block_v[grass_v[i][1]] local i2 = block_v[grass_v[i][2]] local i3 = block_v[grass_v[i][3]] local i4 = block_v[grass_v[i][4]] v_used[i1] = true v_used[i2] = true v_used[i3] = true v_used[i4] = true table.insert(f_code, "if v"..i1.."[4] or v"..i2.."[4] or v"..i3.."[4] or v"..i4.."[4] then " ) table.insert(f_code, [[ ttri( v]]..i1.."[1],v"..i1..[[[2], v]]..i2.."[1],v"..i2..[[[2], v]]..i3.."[1],v"..i3..[[[2], ]]..uv[i][1]..","..uv[i][2]..[[, ]]..uv[i][3]..","..uv[i][4]..[[, ]]..uv[i][5]..","..uv[i][6]..[[, 0,]]..uv.bg..[[, v]]..i1.."[3],v"..i2.."[3],v"..i3..[[[3] ) ]] ) table.insert(f_code, [[ ttri( v]]..i1.."[1],v"..i1..[[[2], v]]..i3.."[1],v"..i3..[[[2], v]]..i4.."[1],v"..i4..[[[2], ]]..uv[i][1]..","..uv[i][2]..[[, ]]..uv[i][5]..","..uv[i][6]..[[, ]]..uv[i][7]..","..uv[i][8]..[[, 0,]]..uv.bg..[[, v]]..i1.."[3],v"..i3.."[3],v"..i4..[[[3] ) ]] ) table.insert(f_code, "end ") end else ---- Full blocks ---- local bx = x + cx * 8 local by = y + cy * 8 local bz = z + cz * 8 local sides = { (y == 7) or isBlockTransp(string.byte(blocks, adr + 8 ), block_id), -- up (y == 0) or isBlockTransp(string.byte(blocks, adr - 8 ), block_id), -- down (x == 0) or isBlockTransp(string.byte(blocks, adr - 1 ), block_id), -- left (x == 7) or isBlockTransp(string.byte(blocks, adr + 1 ), block_id), -- right (z == 0) or isBlockTransp(string.byte(blocks, adr - 64), block_id), -- front (z == 7) or isBlockTransp(string.byte(blocks, adr + 64), block_id), -- back } local sides_check = { "if plr_y > " .. by + 1, "if plr_y < " .. by, "if plr_x < " .. bx, "if plr_x > " .. bx + 1, "if plr_z < " .. bz, "if plr_z > " .. bz + 1, } do if y == 7 and world[cx.."|"..cy+1 .."|"..cz] then sides[1] = isBlockTransp(getblock(bx, by+1, bz), block_id) end if y == 0 and world[cx.."|"..cy-1 .."|"..cz] then sides[2] = isBlockTransp(getblock(bx, by-1, bz), block_id) end if x == 0 and world[cx-1 .."|"..cy.."|"..cz] then sides[3] = isBlockTransp(getblock(bx-1, by, bz), block_id) end if x == 7 and world[cx+1 .."|"..cy.."|"..cz] then sides[4] = isBlockTransp(getblock(bx+1, by, bz), block_id) end if z == 0 and world[cx.."|"..cy.."|"..cz-1] then sides[5] = isBlockTransp(getblock(bx, by, bz-1), block_id) end if z == 7 and world[cx.."|"..cy.."|"..cz+1] then sides[6] = isBlockTransp(getblock(bx, by, bz+1), block_id) end end local anySide = sides[1] or sides[2] or sides[3] or sides[4] or sides[5] or sides[6] if anySide and (palMap ~= curPalMap) then for i = 0, 7 do table.insert(f_code, "poke(".. 0x03FF0+i ..","..tonumber(palMap:sub(i*2+1,i*2+2):reverse(),16)..")") end curPalMap = palMap end ---------------------- for i = 1, 6 do if sides[i] then local i1 = block_v[tri_v[i][1]] local i2 = block_v[tri_v[i][2]] local i3 = block_v[tri_v[i][3]] local i4 = block_v[tri_v[i][4]] v_used[i1] = true v_used[i2] = true v_used[i3] = true v_used[i4] = true table.insert(f_code, sides_check[i] .. " and (v"..i1.."[4] or v"..i2.."[4] or v"..i3.."[4] or v"..i4.."[4]) then " ) table.insert(f_code, [[ ttri( v]]..i1.."[1],v"..i1..[[[2], v]]..i2.."[1],v"..i2..[[[2], v]]..i3.."[1],v"..i3..[[[2], ]]..uv[i][1]..","..uv[i][2]..[[, ]]..uv[i][3]..","..uv[i][4]..[[, ]]..uv[i][5]..","..uv[i][6]..[[, 0,]]..uv.bg..[[, v]]..i1.."[3],v"..i2.."[3],v"..i3..[[[3] ) ]] ) table.insert(f_code, [[ ttri( v]]..i1.."[1],v"..i1..[[[2], v]]..i3.."[1],v"..i3..[[[2], v]]..i4.."[1],v"..i4..[[[2], ]]..uv[i][1]..","..uv[i][2]..[[, ]]..uv[i][5]..","..uv[i][6]..[[, ]]..uv[i][7]..","..uv[i][8]..[[, 0,]]..uv.bg..[[, v]]..i1.."[3],v"..i3.."[3],v"..i4..[[[3] ) ]] ) table.insert(f_code, "end ") end end end end end end end local palMap = "0123456789abcdef" for i = 0, 7 do table.insert(f_code, "poke(".. 0x03FF0+i ..","..tonumber(palMap:sub(i*2+1,i*2+2):reverse(),16)..")") end -- Vertices for x = 0, 8 do table.insert(v_code, "a1 = "..(x + chunk.x * 8).." - plr_x;") for z = 0, 8 do local any_y = false for y = 0, 8 do if v_used[x.."_"..y.."_"..z] then any_y = true break end end if any_y then table.insert(v_code, "c1 = "..(z + chunk.z * 8).." - plr_z;") table.insert(v_code, "c2 = c1 * tycos - a1 * tysin;") table.insert(v_code, "a3 = c1 * tysin + a1 * tycos;") for y = 0, 8 do if v_used[x.."_"..y.."_"..z] then table.insert(v_code, [[ b1 = ]]..(y + chunk.y * 8)..[[ - plr_y b3 = b1 * txcos - c2 * txsin c3 = b1 * txsin + c2 * txcos z1 = (c3 > 0.001) and c3 or 0.001 x1 = a3 / z1 * 120 + 120 y1 = -b3 / z1 * 120 + 68 v]]..x.."_"..y.."_"..z.." = {x1, y1, z1, c3 > 0.4}") end end end end end -- compiling if #v_code < 1 then chunk.render = function()end return end code = table.concat(code)..table.concat(v_code)..table.concat(f_code).." end" local f, err = load(code) assert(f, err) local render_f = f() chunk.render = function() render_f(plr.pos.x, plr.pos.y, plr.pos.z, plr.pitch, plr.yaw) end -- debug local tm = time() - start if not is_empty then if #debug.compileRate < 120 then table.insert(debug.compileRate, tm) else for i = 2, 120 do debug.compileRate[i - 1] = debug.compileRate[i] end debug.compileRate[120] = tm end end end --7.2 ms local upd_t = 0 local function updateChunksQueue() if upd_t > 0 then upd_t = upd_t - 1 return end if not next(updateQueue) then return end local nearest = nil local nearestDist = math.huge for chunk, _ in pairs(updateQueue) do local x = chunk.x * 8 + 4 - plr.pos.x local y = chunk.y * 8 + 4 - plr.pos.y local z = chunk.z * 8 + 4 - plr.pos.z local dist = x * x + y * y + z * z if dist < nearestDist then nearestDist = dist nearest = chunk end end compileChunk(nearest) updateQueue[nearest] = nil upd_t = chunk_update_cooldown end local function updateChunkOnPos(x, y, z) local chunk = world[x.."|"..y.."|"..z] if chunk then updateQueue[chunk] = true end end local function updateChunk(chunk) if chunk then updateQueue[chunk] = true end end ---- world ---- local function loadPalMap(data) for i = 0, 15 do poke4(0x07FE0 + i, tonumber(data:sub(i+1, i+1), 16)) end end local function resetPalMap() for i = 0, 15 do poke4(0x07FE0 + i, i) end end -- world init for x = 0, w_size1 - 1 do for y = 0, w_size2 - 1 do for z = 0, w_size3 - 1 do world[x.."|"..y.."|"..z] = newChunk(x, y, z) end end end local world_type = 0 -- 0 - overworld -- 1 - nether -- 2 - the end local world_entity = {} local droped_items = {} function setblock(x, y, z, id, update) local chunk_x = x // 8 local chunk_y = y // 8 local chunk_z = z // 8 local block_x = x % 8 local block_y = y % 8 local block_z = z % 8 local chunk = world[chunk_x.."|"..chunk_y.."|"..chunk_z] if not chunk then return end if update ~= false then -- nil or true updateChunkOnPos(chunk_x, chunk_y, chunk_z) if block_x == 0 then updateChunkOnPos(chunk_x - 1, chunk_y, chunk_z) end if block_x == 7 then updateChunkOnPos(chunk_x + 1, chunk_y, chunk_z) end if block_y == 0 then updateChunkOnPos(chunk_x, chunk_y - 1, chunk_z) end if block_y == 7 then updateChunkOnPos(chunk_x, chunk_y + 1, chunk_z) end if block_z == 0 then updateChunkOnPos(chunk_x, chunk_y, chunk_z - 1) end if block_z == 7 then updateChunkOnPos(chunk_x, chunk_y, chunk_z + 1) end end local adr = 1 + block_x + 8 * block_y + 64 * block_z local st = chunk.blocks st = st:sub(1, adr - 1) .. string.char(id) .. st:sub(adr + 1, 512) chunk.blocks = st end function getblock(x, y, z) local chunk_x = x // 8 local chunk_y = y // 8 local chunk_z = z // 8 local chunk = world[chunk_x.."|"..chunk_y.."|"..chunk_z] if not chunk then return 0 end local block_x = x % 8 local block_y = y % 8 local block_z = z % 8 local adr = 1 + block_x + 8 * block_y + 64 * block_z return string.byte(chunk.blocks, adr, adr) end local function drop(x, y, z, id, count, t) if id <= 0 then return end t = t or 0 count = count or 1 for i = 1, #droped_items do local item2 = droped_items[i] if item2.id == id then local dist = math.sqrt((item2.x - x) ^ 2 + (item2.y - y) ^ 2 + (item2.z - z) ^ 2) if dist < 1 then item2.x = (item2.x + x) / 2 item2.y = (item2.y + y) / 2 item2.z = (item2.z + z) / 2 item2.count = item2.count + count item2.t = min(item2.t, t) return end end end local item = { x = x, y = y, z = z, id = id, count = count, t = t } table.insert(droped_items, item) end ---- world generator ---- -- Perlin noise local function perlinNoise(octaves, size) local result = {} for x = 0, size-1 do for y = 0, size-1 do result[x.."|"..y] = 0 end end for i = 2, octaves do local oct = {} local step = 1 << i -- Generating data for x = 0, size, step do for y = 0, size, step do oct[x.."|"..y] = R() if x > 0 then local a = oct[x.."|"..y] local b = oct[x-step.."|"..y] for x2 = x-step, x do oct[x2.."|"..y] = a+(b-a)*(x-x2)/step end end end end -- Interpolation for x = 0, size-1 do for y = 0, size-1 do local a = oct[x.."|"..F(y/step)*step] local b = oct[x.."|"..C(y/step)*step] local val = a + (b-a)*(y/step%1) result[x.."|"..y] = result[x.."|"..y] + val * val * i * 1.5 end end end return result end -- Simplex noise local grad3 = { {1,1,0}, {-1,1,0}, {1,-1,0}, {-1,-1,0}, {1,0,1}, {-1,0,1}, {1,0,-1}, {-1,0,-1}, {0,1,1}, {0,-1,1}, {0,1,-1}, {0,-1,-1} } local perm = {} local function initPermutation(seed) math.randomseed(seed) local p = {} for i = 0, 255 do p[i] = i end for i = 255, 0, -1 do local j = math.random(0, i) p[i], p[j] = p[j], p[i] end for i = 0, 255 do perm[i] = p[i] perm[i + 256] = p[i] end end local function simplexDot(g, x, y, z) return g[1] * x + g[2] * y + g[3] * z end local function simplexNoise(xin, yin, zin) local F3 = 1 / 3 local G3 = 1 / 6 local s = (xin + yin + zin) * F3 local i = math.floor(xin + s) local j = math.floor(yin + s) local k = math.floor(zin + s) local t = (i + j + k) * G3 local x0 = xin - (i - t) local y0 = yin - (j - t) local z0 = zin - (k - t) local i1, j1, k1 local i2, j2, k2 if x0 >= y0 then if y0 >= z0 then i1, j1, k1 = 1, 0, 0 i2, j2, k2 = 1, 1, 0 elseif x0 >= z0 then i1, j1, k1 = 1, 0, 0 i2, j2, k2 = 1, 0, 1 else i1, j1, k1 = 0, 0, 1 i2, j2, k2 = 1, 0, 1 end else if y0 < z0 then i1, j1, k1 = 0, 0, 1 i2, j2, k2 = 0, 1, 1 elseif x0 < z0 then i1, j1, k1 = 0, 1, 0 i2, j2, k2 = 0, 1, 1 else i1, j1, k1 = 0, 1, 0 i2, j2, k2 = 1, 1, 0 end end local x1 = x0 - i1 + G3 local y1 = y0 - j1 + G3 local z1 = z0 - k1 + G3 local x2 = x0 - i2 + 2 * G3 local y2 = y0 - j2 + 2 * G3 local z2 = z0 - k2 + 2 * G3 local x3 = x0 - 1 + 3 * G3 local y3 = y0 - 1 + 3 * G3 local z3 = z0 - 1 + 3 * G3 local ii = i % 256 local jj = j % 256 local kk = k % 256 local g0 = grad3[perm[ii + perm[jj + perm[kk]]] % 12 + 1] local g1 = grad3[perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12 + 1] local g2 = grad3[perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12 + 1] local g3 = grad3[perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12 + 1] local t0 = 0.6 - x0 * x0 - y0 * y0 - z0 * z0 local t1 = 0.6 - x1 * x1 - y1 * y1 - z1 * z1 local t2 = 0.6 - x2 * x2 - y2 * y2 - z2 * z2 local t3 = 0.6 - x3 * x3 - y3 * y3 - z3 * z3 local n0, n1, n2, n3 if t0 < 0 then n0 = 0 else t0 = t0 * t0 n0 = t0 * t0 * simplexDot(g0, x0, y0, z0) end if t1 < 0 then n1 = 0 else t1 = t1 * t1 n1 = t1 * t1 * simplexDot(g1, x1, y1, z1) end if t2 < 0 then n2 = 0 else t2 = t2 * t2 n2 = t2 * t2 * simplexDot(g2, x2, y2, z2) end if t3 < 0 then n3 = 0 else t3 = t3 * t3 n3 = t3 * t3 * simplexDot(g3, x3, y3, z3) end return 32 * (n0 + n1 + n2 + n3) end local function generateSimplexNoise(width, height, depth, scale, seed) initPermutation(seed) local noise_table = {} for z = 1, depth do noise_table[z] = {} for y = 1, height do noise_table[z][y] = {} for x = 1, width do noise_table[z][y][x] = simplexNoise(x * scale, y * scale, z * scale) end end end return noise_table end -- Structures stuff local structures = { trees = { { -- Oak tree 1 ".....\n.....\n..l..\n.....\n.....", ".....\n.....\n..l..\n.....\n.....", ".....\n.....\n..l..\n.....\n.....", "####.\n#####\n##l##\n#####\n####.", ".####\n#####\n##l##\n#####\n.###.", ".....\n..#..\n.###.\n..##.\n.....", ".....\n..#..\n.###.\n..#..\n.....", dict = { ["."] = -1, -- void ["l"] = 9 , -- oak log ["#"] = 12, -- oak leaves } }, { -- Birch tree 1 ".....\n.....\n..l..\n.....\n.....", ".....\n.....\n..l..\n.....\n.....", ".....\n.....\n..l..\n.....\n.....", "####.\n#####\n##l##\n#####\n####.", ".####\n#####\n##l##\n#####\n.###.", ".....\n..#..\n.###.\n..##.\n.....", ".....\n..#..\n.###.\n..#..\n.....", dict = { ["."] = -1, -- void ["l"] = 10, -- birch log ["#"] = 13, -- birch leaves } } }, stronghold = { "BBBBBBBBB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBSSSSSSSB\nBBBBBBBBB", "BBBBBBBBB\nB.......B\nB.BBBBB.B\nB.BlllB.B\nB.BlllB.B\nB.BlllB.B\nB.BBBBB.B\nB.......B\nB..BBB..B\nB..BBB..B\nB..BBB..B\nB.......B\nB.......B\nBBBBBBBBB", "BBBBBBBBB\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB..BBB..B\nB..BBB..B\nB.......B\nB.......B\nB.......B\nBBBBBBBBB", "BBBBBBBBB\nB.......B\n|..PPP..|\nB.P...P.B\n|.P...P.|\nB.P...P.B\n|..PPP..|\nB.......B\n|..BBB..|\nB.......B\nB.......B\n|.......|\nB.......B\nBBBBBBBBB", "BBBBBBBBB\nB.......B\n|.......|\nB.......B\n|.......|\nB.......B\n|.......|\nB.......B\n|.......|\nB.......B\nB.......B\n|.......|\nB.......B\nBBBBBBBBB", "BBBBBBBBB\nB.......B\n|.......|\nB.......B\n|.......|\nB.......B\n|.......|\nB.......B\n|.......|\nB.......B\nB.......B\n|.......|\nB.......B\nBBBBBBBBB", "BBBBBBBBB\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nB.......B\nBBBBBBBBB", "BBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB\nBBBBBBBBB", dict = { ["."] = 0 , -- air ["S"] = 1, -- Stone ["l"] = 30, -- Lava ["B"] = 39, -- Stone bricks ["P"] = 36, -- End portal frame ["|"] = 41, -- Iron bars } } } local function loadStrucute(struct, pos_x, pos_y, pos_z, replace, update) local dict = struct.dict for y = 1, #struct do local layer = struct[y] local x, z = 0, 0 for adr = 1, #layer do local chr = layer:sub(adr,adr) if chr == "\n" then x = 0 z = z + 1 else local block_id = dict[chr] if not block_id then trace("Warning! Unknown block: "..chr, 2) block_id = -1 end if block_id >= 0 and (replace or getblock(x + pos_x, y + pos_y, z + pos_z) == 0) then setblock(x + pos_x, y + pos_y, z + pos_z, block_id, update) end x = x + 1 end end end end local function generateWorld() world_type = 0 math.randomseed(0) local worldMap = perlinNoise(5, max(w_size1, w_size3) * 8) for x = 0, 8 * w_size1 - 1 do for z = 0, 8 * w_size3 - 1 do local y = F(worldMap[x.."|"..z] + 8.5) setblock(x, y, z, 2, false) for y2 = 0, y - 1 do setblock(x, y2, z, 1, false) end setblock(x, 0, z, 5, false) if R() > 0.9 then setblock(x, y + 1, z, 22, false) elseif R() > 0.99 then setblock(x, y + 1, z, R(23,24), false) end end end for i = 1, w_size1 * w_size1 * 0.2 do local x = R(0, 8 * w_size1 - 1) local z = R(0, 8 * w_size3 - 1) local y = F(worldMap[x.."|"..z] + 8.5) loadStrucute(randomFrom(structures.trees), x, y, z, true, false) end loadStrucute(structures.stronghold, 5, 4, 5, true, false) end local function generateWorld2() world_type = 0 local landscapeNoise = generateSimplexNoise(w_size1 * 8, w_size2 * 8, w_size3 * 8, 0.05, tstamp()) local cavesNoise = generateSimplexNoise(w_size1 * 8, w_size2 * 8, w_size3 * 8, 0.05, tstamp() + 1) local cavesNoise2 = generateSimplexNoise(w_size1 * 8, w_size2 * 8, w_size3 * 8, 0.2, tstamp() + 2) for y = 8 * w_size2, 1, -1 do local y2 = y / (8 * w_size2) * 2 - 1 local threshold = y2 > 0 and (math.sqrt(y2) * 2 - 1) or -1 for x = 1, 8 * w_size1 do for z = 1, 8 * w_size3 do if y == 1 then setblock(x, y, z, 5, false) -- bedrock else local value = (landscapeNoise[z][y][x] + 1) * 0.5 local value2 = (cavesNoise[z][y][x] + 1) * 0.5 local value3 = (cavesNoise2[z][y][x] + 1) * 0.5 if (value3 - value2) > -0.5 and value > threshold then if value - threshold < 0.5 then if getblock(x, y + 1, z) == 0 then setblock(x, y, z, 2, false) -- grass block if R() > 0.9 then setblock(x, y + 1, z, 22, false) -- grass end setblock(x, y - 1, z, 3, false) -- dirt end else setblock(x, y, z, 1, false) -- stone end end end end end end end local function generateNether() world_type = 1 local noise_data = generateSimplexNoise(w_size1 * 8, w_size2 * 8, w_size3 * 8, 0.05, 0) local noise2_data = generateSimplexNoise(w_size1 * 8, w_size2 * 8, w_size3 * 8, 0.05, 1) for y = 8 * w_size2, 1, -1 do local threshold = math.abs(y / (8 * w_size2) * 2 - 1) + 0.1 for x = 1, 8 * w_size1 do for z = 1, 8 * w_size3 do local value = (noise_data [z][y][x] + 1) * 0.5 local value2 = (noise2_data[z][y][x] + 1) * 0.5 if value < threshold then if value2 < 0.2 then setblock(x, y, z, 33, false) -- soul sand else setblock(x, y, z, 32, false) -- netherrack if threshold - value < 0.2 and R() > 0.95 and (getblock(x, y + 1, z) == 0) then setblock(x, y + 1, z, 34) -- fire end end elseif y < 12 then setblock(x, y, z, 30, false) -- lava end end end end end local function generateEnd() world_type = 2 local noise_data = generateSimplexNoise(w_size1 * 8, w_size2 * 8, w_size3 * 8, 0.05, 0) for x = 1, 8 * w_size1 do for y = 1, 8 * w_size2 do for z = 1, 8 * w_size3 do local px = (x - 4 * w_size1) local py = (y - 4 * w_size2) * 10 local pz = (z - 4 * w_size3) local threshold = math.sqrt(px * px + py * py + pz * pz) * 0.02 local value = (noise_data [z][y][x] + 1) * 0.5 if math.sqrt(value) > threshold then setblock(x, y, z, 40, false) end end end end end generateWorld() --generateNether() --generateEnd() ---- Player ---- plr = { pos = vec3(1, 24, 1), vel = vec3(0, 0, 0), chunk_pos = vec3(0,0,0), last_chunk_pos = vec3(0,0,0), front = vec3(0, 0, 1), speed = 0.1, size = { vec3(-0.4, -1.4, -0.4), vec3(0.4, 0.4, 0.4), }, onGround = true, fly = false, debug = false, yaw = 0, pitch = 0, selBlock = 1, selHotbar = 0, selPos = nil, breaking = { t = 0, pos = vec3(0,0,0) }, textures = 0, } -- inventory local inv = {} local cursorSlot = {id = 0, count = 0} local craftSlot = {} for i = 0, 35 do inv[i] = {id = 0, count = 0} end for i = 0, 8 do craftSlot[i] = {id = 0, count = 0} end inv[0] = {id = 15, count = 1} inv[1] = {id = 9, count = 64} inv[2] = {id = 4, count = 64} inv[3] = {id = 65, count = 64} inv[4] = {id = 66, count = 64} inv[5] = {id = 69, count = 64} inv[6] = {id = 64, count = 64} local function coll(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) --AABB collision return x1 < x4 and x2 > x3 and y1 < y4 and y2 > y3 and z1 < z4 and z2 > z3 end local function collShift(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) -- AABB collision with shift calculation if not coll(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) then return vec3() end local sx, sy, sz if plr.vel.x > 0 then sx = x2 - x3 else sx = x1 - x4 end if plr.vel.y > 0 then sy = y2 - y3 else sy = y1 - y4 end if plr.vel.z > 0 then sz = z2 - z3 else sz = z1 - z4 end local min_shift = min_abs(min_abs(sx, sy), sz) if min_shift == sx then return vec3(sx, 0, 0) elseif min_shift == sy then return vec3(0, sy, 0) elseif min_shift == sz then return vec3(0, 0, sz) end return vec3() end local function raycast(start, finish) local x1, y1, z1 = start:xyz() local x2, y2, z2 = finish:xyz() -- segment direction local dirx, diry, dirz = x2 - x1, y2 - y1, z2 - z1 -- length of one step along axes (only relative) -- n/0 = inf, which is fine for this algorithm local lx, ly, lz = abs(1 / dirx), abs(1 / diry), abs(1 / dirz) -- full tile step, matching direction with the segment local sx, sy, sz -- offset, for handling negative facing local ox, oy, oz -- current tile (offset if facing positive) local x, y, z = F(x1), F(y1), F(z1) -- distance to next tile in each axis local tx, ty, tz = (x1 - x) * lx, (y1 - y) * ly, (z1 - z) * lz if dirx < 0 then sx, ox = -1, 1 else sx, ox = 1, 0 tx = lx - tx end if diry < 0 then sy, oy = -1, 1 else sy, oy = 1, 0 ty = ly - ty end if dirz < 0 then sz, oz = -1, 1 else sz, oz = 1, 0 tz = lz - tz end while true do if tx < ty and tx < tz then x, tx = x + sx, tx + lx if (x + ox) * sx > x2 * sx then return nil end local block_id = getblock(x, y, z) if block_id > 0 then return block_id, {x = x, y = y, z = z}, x1 > x2 and "+x" or "-x" end elseif ty < tz then y, ty = y + sy, ty + ly if (y + oy) * sy > y2 * sy then return nil end local block_id = getblock(x, y, z) if block_id > 0 then return block_id, {x = x, y = y, z = z}, y1 > y2 and "+y" or "-y" end else z, tz = z + sz, tz + lz if (z + oz) * sz > z2 * sz then return nil end local block_id = getblock(x, y, z) if block_id > 0 then return block_id, {x = x, y = y, z = z}, z1 > z2 and "+z" or "-z" end end end end local function playerUpdate() -- Button binds if keyp(49) then plr.debug = not plr.debug end if keyp(22) then plr.fly = not plr.fly end if keyp(7) then plr.textures = (plr.textures + 1) % 4 sync(3, plr.textures, false) end if keyp(58) then render_distance = render_distance + 1 end if keyp(59) then render_distance = max(render_distance - 1, 0) end if keyp(5) then if state == "game" then state = "inventory" poke(0x7FC3F,0,1) else state = "game" poke(0x7FC3F,1,1) mx, my = 0, 0 mtick = 2 for i = 0, 8 do if craftSlot[i].id > 0 then drop(plr.pos.x, plr.pos.y - 1.2, plr.pos.z, craftSlot[i].id, craftSlot[i].count) craftSlot[i].id = 0 craftSlot[i].count = 0 end end end end -- Player movement local plrVec = vec3() if key(23) then plrVec.z = plrVec.z + 1 end if key(19) then plrVec.z = plrVec.z - 1 end if key(1) then plrVec.x = plrVec.x - 1 end if key(4) then plrVec.x = plrVec.x + 1 end if key(64) then plr.speed = 0.5 else plr.speed = 0.1 end if plr.fly then if key(63) then plrVec.y = plrVec.y - 1 end if key(48) then plrVec.y = plrVec.y + 1 end end plrVec = plrVec:normalize() plrVec = plrVec * matrix.rotationY(-plr.yaw) plrVec = plrVec * plr.speed if plr.fly then plr.vel = lerp(plr.vel, plrVec, 0.2) else plr.vel.x = lerp(plr.vel.x, plrVec.x, 0.2) plr.vel.z = lerp(plr.vel.z, plrVec.z, 0.2) -- Gravity plr.vel.y = plr.vel.y - 0.005 -- jumping if plr.onGround and keyp(48) then plr.vel.y = 0.1 end end -- collision local x1 = F(plr.pos.x + plr.vel.x + plr.size[1].x - 1) local y1 = F(plr.pos.y + plr.vel.y + plr.size[1].y - 1) local z1 = F(plr.pos.z + plr.vel.z + plr.size[1].z - 1) local x2 = C(plr.pos.x + plr.vel.x + plr.size[2].x) local y2 = C(plr.pos.y + plr.vel.y + plr.size[2].y) local z2 = C(plr.pos.z + plr.vel.z + plr.size[2].z) plr.onGround = false for x = x1, x2 do for y = y1, y2 do for z = z1, z2 do local plrBox = { plr.pos + plr.vel + plr.size[1], plr.pos + plr.vel + plr.size[2] } if isCollBlock(getblock(x, y, z)) then local result = collShift( plrBox[1].x, plrBox[1].y, plrBox[1].z, plrBox[2].x, plrBox[2].y, plrBox[2].z, x, y, z, x + 1, y + 1, z + 1 ) plr.vel = plr.vel - result if abs(plr.vel.y) < 0.01 then plr.onGround = true end end end end end plr.vel.x = clamp(plr.vel.x, -2, 2) plr.vel.y = clamp(plr.vel.y, -2, 2) plr.vel.z = clamp(plr.vel.z, -2, 2) -- Position updating plr.pos = plr.pos + plr.vel plr.last_chunk_pos = plr.chunk_pos plr.chunk_pos = plr.pos // 8 -- Camera updating if state == "game" then plr.pitch = plr.pitch - my / 80 plr.yaw = plr.yaw - mx / 80 plr.yaw = plr.yaw % (math.pi * 2) plr.pitch = clamp(plr.pitch, -1.5708, 1.5708) plr.front = EulertoVec(plr.pitch, plr.yaw) end -- Inventory buttons for i = 1, 9 do if keyp(27 + i) then plr.selHotbar = i - 1 end end end local function blockPlacement() local breaking_spd = 1 local cur_instrument = nil if in_range(inv[plr.selHotbar].id, 1, 63) then plr.selBlock = inv[plr.selHotbar].id elseif inv[plr.selHotbar].id > 63 then plr.selBlock = nil local item = items_data[inv[plr.selHotbar].id] if item.instrument then cur_instrument = { type = item.instrument, level = item.level, speed = instrument_speed[item.level] } end else plr.selBlock = nil end if state ~= "game" then return end plr.selHotbar = (plr.selHotbar - whl) % 9 local block, pos, dir = raycast(plr.pos, plr.pos + plr.front * 15) plr.selPos = pos if cl1 or clp3 then if pos then if clp3 then -- interactive blocks if not key(64) then if block == 15 then -- crafting table state = "craftingTable" poke(0x7FC3F,0,1) return elseif block == 16 then -- chest -- todo return elseif block == 17 then -- furnace -- todo return elseif block == 36 then -- end portal frame -- todo end end if plr.selBlock then local newPos = pos + dirs[dir] setblock(newPos.x, newPos.y, newPos.z, plr.selBlock) inv[plr.selHotbar].count = inv[plr.selHotbar].count - 1 if inv[plr.selHotbar].count <= 0 then inv[plr.selHotbar].count = 0 inv[plr.selHotbar].id = 0 end end else if cur_instrument and blocks_data[block].instrument == cur_instrument.type then breaking_spd = cur_instrument.speed end plr.breaking.t = plr.breaking.t + breaking_spd if plr.breaking.t <= breaking_spd then plr.breaking.pos = pos plr.breaking.break_t = blocks_data[block].break_t end if pos.x ~= plr.breaking.pos.x or pos.y ~= plr.breaking.pos.y or pos.z ~= plr.breaking.pos.z then plr.breaking.t = 0 plr.breaking.pos = pos end if plr.breaking.t > plr.breaking.break_t then setblock(pos.x, pos.y, pos.z, 0) plr.breaking.t = 0 drop(pos.x + 0.5, pos.y + 0.2, pos.z + 0.5, blocks_data[block].drop or block, 1, 55) end end end end if not cl1 then plr.breaking.t = 0 end end local function chunksGC() if plr.chunk_pos.x == plr.last_chunk_pos.x and plr.chunk_pos.y == plr.last_chunk_pos.y and plr.chunk_pos.z == plr.last_chunk_pos.z then return end local x1 = max(plr.last_chunk_pos.x - render_distance, 0) local z1 = max(plr.last_chunk_pos.z - render_distance, 0) local x2 = min(plr.last_chunk_pos.x + render_distance, w_size1 - 1) local z2 = min(plr.last_chunk_pos.z + render_distance, w_size3 - 1) local x3 = max(plr.chunk_pos.x - render_distance, 0) local z3 = max(plr.chunk_pos.z - render_distance, 0) local x4 = min(plr.chunk_pos.x + render_distance, w_size1 - 1) local z4 = min(plr.chunk_pos.z + render_distance, w_size3 - 1) --[[ x1,z1--------* | | | | | | | x3,z3---|-----* | | | | | | | | *--------x2,z2 | | | | | | | *---------x4,z4 ]] for x = x1, x2 do for z = z1, z2 do if not (x >= x3 and z >= z3 and x <= x4 and z <= z4) then for y = 0, w_size2 - 1 do local chunk = world[F(x).."|"..y.."|"..F(z)] chunk.render = nil end end end end end ---- GUI ---- local function drawBlockInSlot(uv, pos_x, pos_y) local v = { {pos_x + 0 , pos_y + 12, 98 }, {pos_x + 8 , pos_y + 9 , 103}, {pos_x + 0 , pos_y + 3 , 94 }, {pos_x + 8 , pos_y , 99 }, {pos_x + 8 , pos_y + 16, 93 }, {pos_x + 16 , pos_y + 12, 98 }, {pos_x + 8 , pos_y + 7 , 89 }, {pos_x + 16 , pos_y + 3 , 94 }, } local tri_v = { {4, 8, 7, 3, 1}, -- up {7, 8, 6, 5, 4}, -- right {3, 7, 5, 1, 5}, -- front } if uv.palmap then loadPalMap(uv.palmap) end for i = 1, 3 do local uv_cur = uv[tri_v[i][5]] local i1 = tri_v[i][1] local i2 = tri_v[i][2] local i3 = tri_v[i][3] local i4 = tri_v[i][4] ttri( v[i1][1], v[i1][2], v[i2][1], v[i2][2], v[i3][1], v[i3][2], uv_cur[1],uv_cur[2], uv_cur[3],uv_cur[4], uv_cur[5],uv_cur[6], 0, uv.bg, v[i1][3], v[i2][3], v[i3][3] ) ttri( v[i1][1], v[i1][2], v[i3][1], v[i3][2], v[i4][1], v[i4][2], uv_cur[1],uv_cur[2], uv_cur[5],uv_cur[6], uv_cur[7],uv_cur[8], 0, uv.bg, v[i1][3], v[i3][3], v[i4][3] ) end resetPalMap() end local function drawSlot(pos_x, pos_y, slotData, frame, craftSlot) if slotData.id == 0 then slotData.count = 0 end if slotData.count <= 0 then slotData.id = 0 slotData.count = 0 end local sel = in_range(mx, pos_x - 1, pos_x + 18) and in_range(my, pos_y - 1, pos_y + 18) local taked = false if slotData == cursorSlot then sel = false end if frame ~= false then rect(pos_x - 1, pos_y - 1, 19, 19, 1) rect(pos_x, pos_y, 19, 19, 15) rect(pos_x, pos_y, 18, 18, sel and 10 or 7) pix(pos_x + 18, pos_y - 1, 7) pix(pos_x - 1, pos_y + 18, 7) end if slotData and slotData.id > 0 then local spr_id, spr_bg local palmap local block_spr = false if slotData.id < 64 then local texture = blocks_data[slotData.id].texture spr_id = texture[4] or texture[2] or texture[1] spr_bg = blocks_data[slotData.id].uv.bg or 13 palmap = blocks_data[slotData.id].palmap block_spr = not blocks_data[slotData.id].grass else spr_id = items_data[slotData.id].texture spr_bg = items_data[slotData.id].bg or 2 palmap = items_data[slotData.id].palmap end local num = slotData.count spr_id = 2 * (spr_id % 8) + 32 * (spr_id // 8) if palmap then loadPalMap(palmap) end if block_spr then drawBlockInSlot(blocks_data[slotData.id].uv, pos_x + 1, pos_y + 1) else vbank(0) spr(spr_id, pos_x + 1, pos_y + 1, spr_bg, 1, 0, 0, 2, 2) vbank(1) spr(spr_id, pos_x + 1, pos_y + 1, spr_bg, 1, 0, 0, 2, 2) end if palmap then resetPalMap() end if num ~= 1 then vbank(0) print(num, pos_x + (num < 10 and 13 or 9) , pos_y + 12, 0, true, 1, true) print(num, pos_x + (num < 10 and 13 or 9) , pos_y + 11, 15, true, 1, true) vbank(1) print(num, pos_x + (num < 10 and 13 or 9) , pos_y + 12, 0, true, 1, true) print(num, pos_x + (num < 10 and 13 or 9) , pos_y + 11, 15, true, 1, true) end end if sel then c_id = 1 if craftSlot and (clp1 or clp3) then if cursorSlot.id == 0 then cursorSlot.id = slotData.id cursorSlot.count = slotData.count taked = true elseif cursorSlot.id == slotData.id and (cursorSlot.count + slotData.count) <= 64 then cursorSlot.id = slotData.id cursorSlot.count = cursorSlot.count + slotData.count taked = true end elseif clp1 then if cursorSlot.id ~= slotData.id then cursorSlot.id, slotData.id = slotData.id, cursorSlot.id cursorSlot.count, slotData.count = slotData.count, cursorSlot.count taked = true else slotData.count = slotData.count + cursorSlot.count cursorSlot.count = 0 cursorSlot.id = 0 taked = true end elseif clp3 and not craftSlot then if cursorSlot.id == 0 then cursorSlot.id = slotData.id cursorSlot.count = C(slotData.count / 2) slotData.count = slotData.count - cursorSlot.count if slotData.count <= 0 then slotData.id = 0 end taked = true elseif slotData.id == 0 or (slotData.id == cursorSlot.id) then slotData.id = cursorSlot.id slotData.count = slotData.count + 1 cursorSlot.count = cursorSlot.count - 1 if cursorSlot.count < 0 then cursorSlot.id = 0 end taked = true end end end return sel, taked end local function processCraft() local craftResult = {id = 0, count = 0} local craftGrid = {} for j = 0, 8 do craftGrid[j] = craftSlot[j].id end -- shifting for _ = 1, 2 do if craftGrid[0] == 0 and craftGrid[1] == 0 and craftGrid[2] == 0 then craftGrid[0] = craftGrid[3] craftGrid[1] = craftGrid[4] craftGrid[2] = craftGrid[5] craftGrid[3] = craftGrid[6] craftGrid[4] = craftGrid[7] craftGrid[5] = craftGrid[8] craftGrid[6] = 0 craftGrid[7] = 0 craftGrid[8] = 0 end if craftGrid[0] == 0 and craftGrid[3] == 0 and craftGrid[6] == 0 then craftGrid[0] = craftGrid[1] craftGrid[3] = craftGrid[4] craftGrid[6] = craftGrid[7] craftGrid[1] = craftGrid[2] craftGrid[4] = craftGrid[5] craftGrid[7] = craftGrid[8] craftGrid[2] = 0 craftGrid[5] = 0 craftGrid[8] = 0 end end -- looking for needed craft for i = 1, #crafts do local craft = crafts[i] local matchCraft = true for j = 0, 8 do if type(craft[j + 1]) == "number" then if craft[j + 1] ~= craftGrid[j] then matchCraft = false break end else if not isInTable(craft[j + 1], craftGrid[j]) then matchCraft = false break end end end if matchCraft then craftResult.id = craft.result.id craftResult.count = craft.result.count end end return craftResult end local function inventory() vbank(1) cls(0) rect(28, 4, 186, 1, 15) rect(28, 135, 186, 1, 7) rect(27, 5, 1, 130, 15) rect(214, 5, 1, 130, 7) rect(28, 5, 186, 130, 10) print("Inventory", 29, 7, 1) print("Inventory", 29, 6, 7) for x = 0, 8 do for y = 0, 3 do local id = x + (y + 1) % 4 * 9 local hotbar = (y == 3) drawSlot(x * 20 + 32, y * 20 + 52 + (hotbar and 4 or 0), inv[id]) end end -- crafts drawSlot(132, 8, craftSlot[0]) drawSlot(152, 8, craftSlot[1]) drawSlot(132, 28, craftSlot[3]) drawSlot(152, 28, craftSlot[4]) local craftResult = processCraft() local sel, taked = drawSlot(192, 19, craftResult, true, true) if craftResult.id > 0 and taked then for i = 0, 8 do craftSlot[i].count = craftSlot[i].count - 1 if craftSlot[i].count <= 0 then craftSlot[i].id = 0 end end end drawSlot(mx - 8, my - 8, cursorSlot, false) end local function craftingTable() vbank(1) cls(0) rect(28, 4, 186, 1, 15) rect(28, 135, 186, 1, 7) rect(27, 5, 1, 130, 15) rect(214, 5, 1, 130, 7) rect(28, 5, 186, 130, 10) for x = 0, 8 do for y = 0, 2 do local id = x + (y + 1) * 9 drawSlot(x * 20 + 32, y * 20 + 74, inv[id]) end end for x = 0, 2 do for y = 0, 2 do local id = x + y * 3 drawSlot(x * 20 + 32, y * 20 + 10, inv[id]) end end drawSlot(112, 10, craftSlot[0]) drawSlot(132, 10, craftSlot[1]) drawSlot(152, 10, craftSlot[2]) drawSlot(112, 30, craftSlot[3]) drawSlot(132, 30, craftSlot[4]) drawSlot(152, 30, craftSlot[5]) drawSlot(112, 50, craftSlot[6]) drawSlot(132, 50, craftSlot[7]) drawSlot(152, 50, craftSlot[8]) local craftResult = processCraft() local sel, taked = drawSlot(182, 30, craftResult, true, true) if craftResult.id > 0 and taked then for i = 0, 8 do craftSlot[i].count = craftSlot[i].count - 1 if craftSlot[i].count <= 0 then craftSlot[i].id = 0 end end end drawSlot(mx - 8, my - 8, cursorSlot, false) end local function addToInventory(id, count) for i = 0, 35 do local slot = inv[i] if slot.id == id then if count + slot.count <= 64 then slot.count = slot.count + count count = 0 else count = count + slot.count - 64 slot.count = 64 end end if count <= 0 then return true, 0 end end for i = 0, 35 do local slot = inv[i] if slot.id == 0 then slot.id = id slot.count = min(count, 64) count = count - slot.count end if count <= 0 then return true, 0 end end return false, count end ---- Rendering ---- local function drawBlock(uv, pos_x, pos_y, pos_z, global_pos, pitch, yaw, size, rot) local txsin=math.sin(pitch) local txcos=math.cos(pitch) local tysin=math.sin(yaw) local tycos=math.cos(yaw) local hsize = size / 2 -- half size local v = { vec3(-hsize, -hsize, -hsize), vec3(-hsize, -hsize, hsize), vec3(-hsize, hsize, -hsize), vec3(-hsize, hsize, hsize), vec3( hsize, -hsize, -hsize), vec3( hsize, -hsize, hsize), vec3( hsize, hsize, -hsize), vec3( hsize, hsize, hsize), } if rot then for i = 1, 8 do v[i] = v[i]:rotate_xz(rot) end end for i = 1, 8 do local a1 = v[i].x + (global_pos and pos_x or 0) local b1 = v[i].y + (global_pos and pos_y or 0) local c1 = v[i].z + (global_pos and pos_z or 0) local c2 = c1 * tycos - a1 * tysin local a3 = c1 * tysin + a1 * tycos + (global_pos and 0 or pos_x) local b3 = b1 * txcos - c2 * txsin + (global_pos and 0 or pos_y) local c3 = b1 * txsin + c2 * txcos + (global_pos and 0 or pos_z) local z1 = (c3 > 0.001) and c3 or 0.001 local x1 = a3 / z1 * 120 + 120 local y1 = -b3 / z1 * 120 + 68 v[i] = {x1, y1, z1, c3 > 0} end local tri_v = { {4, 8, 7, 3}, -- up {1, 5, 6, 2}, -- down {4, 3, 1, 2}, -- left {7, 8, 6, 5}, -- right {3, 7, 5, 1}, -- front {8, 4, 2, 6} -- back } if uv.palmap then loadPalMap(uv.palmap) end for i = 1, 6 do local i1 = tri_v[i][1] local i2 = tri_v[i][2] local i3 = tri_v[i][3] local i4 = tri_v[i][4] ttri( v[i1][1], v[i1][2], v[i2][1], v[i2][2], v[i3][1], v[i3][2], uv[i][1],uv[i][2], uv[i][3],uv[i][4], uv[i][5],uv[i][6], 0, uv.bg, v[i1][3], v[i2][3], v[i3][3] ) ttri( v[i1][1], v[i1][2], v[i3][1], v[i3][2], v[i4][1], v[i4][2], uv[i][1],uv[i][2], uv[i][5],uv[i][6], uv[i][7],uv[i][8], 0, uv.bg, v[i1][3], v[i3][3], v[i4][3] ) end resetPalMap() end local function rendering() -- background vbank(0) cls(select(world_type + 1, 13, 3, 1)) -- Chunk rendering local chunk_x = plr.chunk_pos.x local chunk_z = plr.chunk_pos.z local x1 = max(chunk_x - render_distance, 0) local z1 = max(chunk_z - render_distance, 0) local x2 = min(chunk_x + render_distance, w_size1 - 1) local z2 = min(chunk_z + render_distance, w_size3 - 1) for x = x1, x2 do for z = z1, z2 do for y = 0, w_size2 - 1 do local chunk = world[F(x).."|"..y.."|"..F(z)] if chunk.render then chunk.render() else updateChunk(chunk) end end end end if plr.selPos and plr.breaking.t > 0 then local pos = plr.selPos - plr.pos + 0.5 drawBlock(breakingUV[min(F(plr.breaking.t * 10 / plr.breaking.break_t + 0.5), 9)], pos.x, pos.y, pos.z, true, plr.pitch, plr.yaw, 1.01) end -- rendering dropped items --if keyp(17) then drop(plr.pos.x, plr.pos.y - 1.2, plr.pos.z, 1) end for i = #droped_items, 1, -1 do local item = droped_items[i] local dist = (plr.pos - item):length() item.t = item.t + 1 if item.t > 60 then if dist < 3 then local spd = 0.6 - dist * dist * 0.1 spd = clamp(spd, 0, 1) item.x = lerp(item.x, plr.pos.x, spd) item.y = lerp(item.y, plr.pos.y - 0.3, spd) item.z = lerp(item.z, plr.pos.z, spd) end if dist < 0.5 then local suc, count = addToInventory(item.id, item.count) if suc then table.remove(droped_items, i) else item.count = count item.t = 0 item.y = item.y - 1.2 end end end if dist < 15 then local size = math.log(item.count, 8) + 1 drawBlock( blocks_data[item.id].uv, item.x - plr.pos.x, item.y - plr.pos.y + math.sin(item.t * 0.05) * 0.1, item.z - plr.pos.z, true, plr.pitch, plr.yaw, 0.3 * size, -item.t * 0.02 ) end end -- cross pix(120, 68, 15) if inv[plr.selHotbar].id >= 64 then print_mid(items_data[inv[plr.selHotbar].id].name, 120, 107, 1) print_mid(items_data[inv[plr.selHotbar].id].name, 120, 106, 15) elseif inv[plr.selHotbar].id > 0 then print_mid(blocks_data[inv[plr.selHotbar].id].name, 120, 107, 1) print_mid(blocks_data[inv[plr.selHotbar].id].name, 120, 106, 15) end -- Hand vbank(1) cls(0) vbank(0) if plr.selBlock then drawBlock(blocks_data[plr.selBlock].uv, 2.2, -1, 3, false, 0, 0.9, 1) end -- copying vbank 0 to vbank 1 vbank(1) cls(0) ttri(0,0,240,0,0,136,0,0,240,0,0,136,2) ttri(240,136,240,0,0,136,240,136,240,0,0,136,2) vbank(0) respal() darkpal(0.5) -- Hotbar if state == "game" then vbank(1) for i = 0, 8 do rect(i * 19 + 35, 116, 20, 20, 0) drawSlot(i * 19 + 36, 117, inv[i], false) end vbank(0) rectb(plr.selHotbar * 19 + 35, 116, 20, 20, 15) vbank(1) rectb(plr.selHotbar * 19 + 35, 116, 20, 20, 15) end if state == "inventory" then inventory() end if state == "craftingTable" then craftingTable() end end ---- debug GUI ---- function debug.printRates() local maxLen = 0 for _, val in ipairs(debug.medRate) do maxLen = max(maxLen, #val.name) end for i, val in ipairs(debug.medRate) do print(val.name, 1, 138 - i * 8, 1, true, 1, true) print(val.name, 1, 137 - i * 8, 15, true, 1, true) print(stf("%.2f ms.",val.val), maxLen * 4 + 8, 138 - i * 8, 1, false, 1, true) print(stf("%.2f ms.",val.val), maxLen * 4 + 8, 137 - i * 8, 15, false, 1, true) end end function debug.printInfo() local text = { stf("%0.1f FPS", debug.medFPS), stf("pos X: %0.1f Y: %0.1f Z: %0.1f", plr.pos.x, plr.pos.y, plr.pos.z), stf("vel X: %0.1f Y: %0.1f Z: %0.1f", plr.vel.x, plr.vel.y, plr.vel.z), stf("Camera: %0.1f %0.1f",math.deg(plr.yaw), math.deg(plr.pitch)), stf("%.1f mb.", collectgarbage("count") / 1024), stf("%.1f ms. per chunk", debug.medComp), } for i = 1, #text do print(text[i], 1, (i - 1) * 8 + 2, 1) print(text[i], 1, (i - 1) * 8 + 1, 15) end end function debug.drawRate(x, y, data, scale, name) rect(x, y, 32, 20, 1) rectb(x, y, 32, 20, 7) for i = 1, min(#data, 30) do local val = F(data[i] * scale + 0.5) rect(x + i, y + 19 - val, 1, val, 15) end end ---- Main loop ---- collectgarbage("collect") collectgarbage("stop") music(0) poke(0x7FC3F,1,1) function TIC() debug.start() t = t + 1 c_id = 0 -- updating mouseUpdate() playerUpdate() blockPlacement() debug.addtime("updating") -- chunk updating updateChunksQueue() debug.addtime("chunks upd") -- chunks garbage collector chunksGC() debug.addtime("chunks gc") -- rendering rendering() debug.addtime("rendering") -- collectgarbage collectgarbage("collect") debug.addtime("collectgarbage") poke4(0x07FF6,c_id) -- debug debug.finish() if plr.debug then debug.printRates() debug.printInfo() --debug.drawRate(205, 110, debug.frame, 0.5) --debug.drawRate(205, 85 , debug.compileRate, 0.5) end end