From 1e665378f8a2a9d79f9124a2c56f147c3c0aaecd Mon Sep 17 00:00:00 2001 From: crumblingstatue Date: Mon, 17 Apr 2023 13:41:51 +0200 Subject: [PATCH] Make tile ids strongly typed between bg/mid/fg --- Cargo.lock | 56 ++++-- Cargo.toml | 1 + design/data.md | 11 ++ res/graphics/tiles/unknown_bg.png | Bin 0 -> 4705 bytes res/graphics/tiles/unknown_fg.png | Bin 0 -> 4636 bytes res/graphics/tiles/unknown_mid.png | Bin 0 -> 4632 bytes src/app.rs | 44 ++--- src/game.rs | 8 +- src/inventory.rs | 29 +-- src/tiles.rs | 289 ++++++++++++++++++++++++----- src/tiles/tiledb_edit_ui.rs | 118 +++++++----- src/world.rs | 27 ++- src/world/serialization.rs | 14 +- src/worldgen.rs | 29 +-- tiles.dat | Bin 237 -> 204 bytes 15 files changed, 448 insertions(+), 178 deletions(-) create mode 100644 design/data.md create mode 100644 res/graphics/tiles/unknown_bg.png create mode 100644 res/graphics/tiles/unknown_fg.png create mode 100644 res/graphics/tiles/unknown_mid.png diff --git a/Cargo.lock b/Cargo.lock index e7d6abc..1a59f70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,6 +158,17 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +[[package]] +name = "bitfield-struct" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc92b6a6ac8f8176ab4764440f5129ad73d557c532b7f5c324a71846fd25a9c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.15", +] + [[package]] name = "bitflags" version = "1.3.2" @@ -296,9 +307,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -400,7 +411,7 @@ dependencies = [ [[package]] name = "egui-inspect" version = "0.1.0" -source = "git+https://github.com/crumblingstatue/egui-inspect.git#5cf1f05c0f4f6625eb9a46ee0faebdb27919f9bf" +source = "git+https://github.com/crumblingstatue/egui-inspect.git#77b02370966aad6be6eeb94ce88ae9268986fc0d" dependencies = [ "egui", "egui-inspect-derive", @@ -409,11 +420,11 @@ dependencies = [ [[package]] name = "egui-inspect-derive" version = "0.1.0" -source = "git+https://github.com/crumblingstatue/egui-inspect.git#5cf1f05c0f4f6625eb9a46ee0faebdb27919f9bf" +source = "git+https://github.com/crumblingstatue/egui-inspect.git#77b02370966aad6be6eeb94ce88ae9268986fc0d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.15", ] [[package]] @@ -504,7 +515,7 @@ dependencies = [ "flume", "half", "lebe", - "miniz_oxide", + "miniz_oxide 0.6.2", "rayon-core", "smallvec", "zune-inflate", @@ -519,6 +530,15 @@ dependencies = [ "instant", ] +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + [[package]] name = "flate2" version = "1.0.25" @@ -526,7 +546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.6.2", ] [[package]] @@ -930,6 +950,7 @@ name = "mantle-diver" version = "0.1.0" dependencies = [ "anyhow", + "bitfield-struct", "clap", "derivative", "directories", @@ -980,6 +1001,16 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + [[package]] name = "nanorand" version = "0.7.0" @@ -1166,14 +1197,15 @@ checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" [[package]] name = "png" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" dependencies = [ "bitflags", "crc32fast", + "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -1978,9 +2010,9 @@ dependencies = [ [[package]] name = "zune-inflate" -version = "0.2.51" +version = "0.2.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01728b79fb9b7e28a8c11f715e1cd8dc2cda7416a007d66cac55cebb3a8ac6b" +checksum = "440a08fd59c6442e4b846ea9b10386c38307eae728b216e1ab2c305d1c9daaf8" dependencies = [ "simd-adler32", ] diff --git a/Cargo.toml b/Cargo.toml index d92c34b..fae2495 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,7 @@ directories = "5.0.0" texture_packer = "0.25.0" walkdir = "2.3.3" image = "0.24.6" +bitfield-struct = "0.4.1" [dependencies.s2dc] #git = "https://github.com/crumblingstatue/s2dc.git" diff --git a/design/data.md b/design/data.md new file mode 100644 index 0000000..8cc7246 --- /dev/null +++ b/design/data.md @@ -0,0 +1,11 @@ +Tile + +9 bits bg +9 bits mid +9 bits fg 32 bits +3 bits slope +2 bits fg state (0: fg has ore, 1: bg has ore, 2: both have ores) + +5 bits liquid type +6 bits paint 16 bits +5 bits reserved \ No newline at end of file diff --git a/res/graphics/tiles/unknown_bg.png b/res/graphics/tiles/unknown_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..cf5f15e2baee5c436749930a10c0cbf01a54d09a GIT binary patch literal 4705 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}hpIv%N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsJTl+~z&3!1E`)tFJ+x(U>nYXr*+?AGrrE3txKL{kfEA{bv4m zZ5yc>CNC!GPMxB(z?D1PLX15tz3bM_=DjTyr`k6k@ZgM-T&Viq{!^0nw+?~Y{C5~%*fz`)p&>FgZf>Ff;i z4Ff~PoZ5-D9)|-&TKzA3Ee&ybqo6ctq18=SSD9?lt^ma=Tx+dn?D@h!%S1&}udgZl z;KBJvS2cHUUdOktN#O_cqgRiXyiiiTH(f01$d3n~?9Np`FSuXZaAAePS*|0DzT3~1 z7%8R|uTJ_P%E+VOVyb0)ddB1>A~x5r+t$?V@BXOszPf&$ooT+|0d=9{GZSwekv?KP zd)vXv`4)$~HhIWZ2e^v#kynHlo)Eyl=^5=7;?4b zl=vpyFw6YHYg(q)-c8h-zI;la_^R7{CoSr(Ng!|Zw;qq6JDI0;CplGpAe^o414BZG=JJ~Fj`^DwOP@> zWtQ_hw53hm#mL9k_)#f!ef6H*+pF{b-^)Dzo;{AMXx^y=z55IdycL-t5hW46K32*3 zxq68y`AMmI6}bfrAYfx(QIMFNom!%hl$xHIXRGvn_kJaX%oJOta8q9c-vZ~}1OnC3`zAn+mIn+=ATHl0=1y+?>2(s|s5su(?)w#a19;eI*63l9Fs& zr3l{u1?T*tR0R_~6Fmc6*NV(CBPBa71)HLjG^-#NH>eRsDQUJ!86_nJR{Hwo<>h+i z#(Mch>H3D2mX`VkM*2oZxJ9 zL6DxATL9Kokz0VGvLrJN5m+d`0m*>9gY1xs+yc0{D5_z82P+1Lk(En+aw*7po-VdZ zAp5OS@{==DtiVj;G=nq?OEUvq3)5r^T@wpaGhIuQL}OhGi=-4IlN3Xv#3V~3qdfD9 zOA_;vQ$a>mOQ zKuCmS=B5UhB!WWI(9FWn+{nzr!q~vX$kfsVp(rf1s5mn}4`imHfu1o$1{5t;{zaLo zc_oRUbZV<)2-Z=NTVUl}l$uzQUlfv`pJS^8a*~3Po*~3JAZg#!lEjq6l0=upl2ltI zBLgF2D+3cNL-P6k8=|a)oKh#F7+@(=5!* zP0UPmEmO@?bxll6({wE?63uiIEetITjLgyujM7q3O)t(*D=AMbN_9+6%`350a?i{y z0Ed-=1~{TLQB{{`q=I6>z{ptFz(f}_!1N(rw9yBZ889E)=wpNlL;+GEW5=Zc5ess0 zv*WVS2bXl9QV(JvsMMh)hQKonDYi=GO7?cU=1t$rz`($kTxkJ{B+)3&%nUIS>O>_%)r1c48n{I zv*t)JFfg!}c>21sKW7o-5*1H&{J4~Xfr-b{#W5t}@Y(67vxNgij@5gnSv^ynxzTg+ z1rwj{(3gucSQZ9|FXi4Wv`gr_Ud-?E9VJh_?vy+?VmT7a-4xk!skhss#xdh{%d&G8 zXHU1fd@{&)NPb%(qhed&05DUK3)^e_z|ZbWSy^+S*F-n(FMCZ`VHEU){V!t@psCXMXBMDV&V| zweRiI=3bqscDUZ_f!Ln^I{GdtNy2^1<)32bbGk0p-X0v_e``a;shvgp4I1;V?Y(JT zy3e37Z`oeI^Xs1fj=FeNK}hjqd{2`8lJeX`-E5b9>fMx{ewxyd@vV>jqJ=@=X0JN$ zHvt)GE1a++NIFS5U zTk|pZ{b$A**EIFl-4h945OIokXMI8KO%n~3l6yAU&tuM(%SA5UF0?cl*fynalM-=<3J%KY%;a`nFWlL@B< z>p5h+xY{{uGxl@txpe77)~w&(G>dk>oX@oQQRGwRPx{SOHol5GjcS?B8<)GEXEc_a cck}iK^JvlCy9@XZO#-DPPgg&ebxsLQ0Boz&i2wiq literal 0 HcmV?d00001 diff --git a/res/graphics/tiles/unknown_fg.png b/res/graphics/tiles/unknown_fg.png new file mode 100644 index 0000000000000000000000000000000000000000..3be1c3c0a0604bcfc93931439a71b7f445741852 GIT binary patch literal 4636 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}hpR#&N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsJTlMDrb1;Q9Sr#G0v6XxHdA2dX^w_s;tnWEK z>!}FpEJ|j`RCLr5Vx624qhg}nWFzgClcd@RWz`(%RlIiRm;OXoP z^9}<;#hluSwjPHAL|XkXdo2xdd842-X`$6kS67*A(XIf+D_m=>X6*UGKg&c#Q?IWn z`{2R(M^`m>Z(hf@u1Vns^P^Xfmb_3>y*FJf>d21=pX|<6KQFjn+i+op!C9^&jK15? zmKZ6f6|YYEAj-(2;9{y}e0s*@B_cN0uiMtt?C<`l^S-)%ot}qdA%gU<8tMp!}f1} zsTOHI(Q2NU%ov(6A=dtf{GWMiLubs&QEe4=IN$xaribxh?1IShIq#E?XU=2zm;S)( z{g2hW3Ew7vsdDd@WBhyjz|m6o;BO75WfNYUoZx$N>Yos&g$#Sb$#`o-P^14{@=?y|DHXLt7zV-1ikwV47?SYArU1JzCKpT z`MG+DDfvmMdKI|^3?N`*Ur~^loSj;tkd&I9nP;o?e)oPQh0GLNrEpVU1K$GY)Qn7z zs-o23D!-8As_bOT6eW8*E}IIgirj+S)RIJnirk#MVyg;UC9t_xdBs*BVSOb9u#%E& zTcrr!00rm#qErPFJrg|xUDt}tG9x8BE(M#Slr*a#7dNO8MJZ{vN*N_31y=g{<>lpi z<;HsXMd|v6mX?*7iAWdWaj57fXqxx z$}cUkRZ`+oP*8vxUXfei>kBtNuNWE%$@#hZ6^RA?&DLkj~#gJiQ5UDMQ*BwZ8B)HGcSgCql8vo!Nm)5IhT6GIDAB%?g@ zic1pnl2buORpb`vWoD*WSy~tynVFlI=q4tnnChBXCK~G|T3DFrrkWZXB%4_z8=IsW zAQ|Cbl$oBHmzaa>Dv(hrnJHGLmL`@KCaEd9DP|Vtx+bZ{sk)XXsfM~nDTb!W#)ioj z#>r-2qf(Ns-13WZ6H9EBGIJBtQ}qk-(!mm-0Jm}s@U&Gj(u3Fv7755nEJ@2R%C%MU z$;>OQKqw8#%uNk0Nd$$ap_zrDxsjQLg^7WYfvJflLQz<1QE_H|9>`2X13hCCunZ_# zto(~IQ}ap^LFv?1$q+1Fky~KpT$Gwvl3x^(pPyr^1ag3ak)9#MIUs4@)RM%M#F9jp z#FA87B_jhPV=Ds_D?{@TLnA9ALn|W_Z381K10?nNDVb@NgjCysGKUQ$$~`iROY(~< z!9tK66`WcK;X$}LnIP2)3JTy%VU?H+@j`K8S!xQ{8*r)QjKsY3)D&AKXmW*V$;6Tr zj1!a1QA!Em- z01*pvakJyH(Fd1wpi&QFAgI)#C5FZYEv-;c7`23?@Er}V(cmH}1V~amnz}}Vi=+@B zN%3gvqFQiqA-Yqkc`3F^lta zX_FW8sR~ZwN;v4dZfVHLw&Q-R!Bc*DmNA^Ueqx`x`P0d77-slS4Bj>MX4I559)XT7 zUCL~(fj+$pmRkr4X-#0;Vx*+HYsD*upj!Vj$CmR(LBiVHYnx}h;#-gw-SEW3AuC$p z?_cG%ZPL{%W^+v3EWdA3K*K|O=Iih0^OQ>IF<({_`SpAHLv3yL!}3|n7(Hs%yM8oX zcSqpkBQ56tyRCVi+S?iGh=-?l)YbJiets_A_MGVwPrt=a$!$ek0qboWbQRZ4yO31y zL?~&7s>W%7uRlc(>oQ8V&ArpaGx7cWplRGIVl^)=jW1}4?r?m2Sh#J|?&Fd-{{2n+ zarA^wrKbnSowT&n9l9E)4;(mf;6q1e>%!Qme#a;O?b~)-FPE6NdDG>4j3*k}AKE*= zeOk&>AMsQ2omZA&Ok&#N_00PW42-6{W_x_D?Y_zmwl(=246}|cIMBf<^$C;)JYD@< J);T3K0RZIXsqFv& literal 0 HcmV?d00001 diff --git a/res/graphics/tiles/unknown_mid.png b/res/graphics/tiles/unknown_mid.png new file mode 100644 index 0000000000000000000000000000000000000000..03676255846fc7e15d1a621ece32adad7b66047c GIT binary patch literal 4632 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANL}hpIv%N`ey06$*;-(=u~X z6-p`#QWa7wGSe6sDsJTl+~z&3!1E`)tFJ+x(U>nYXr*+?AGrrE3txKL{kfEA{bv4m zZ5yc>CNC!GPMxB(z?D1PLX15tz3bM_=DjTyr`k6k@ZgM-T&Viq{!^0nw+za7cZ8uxP}0|R4Arn7T^r?WH6 zHw+9Fb808rdK?ZAY4yMCwKT-#je^pog;qCRU1hRGy8;xiaILkPvF8i_EE5$?y}qXG zg9qmyUDe#Zc^%)nCWRl&k6t}m@ygKQFC?k)8i>a3J=^2xkh}c}eZd+5czx$)k`|A32cBc7;2h@d*&rG~^MEZ#F z>}>}t=UW`|+T>N^XOkGze55}nJnGM}oi8>WFjh`ev-Ouz6zh&%Q(~w+Q|hBhVaU~z zQ{tO+!z}X)uW6ZHdpCK%!JO;i({}oqHmQhhWZ_g2xf0;UYL>L+^^ypW%aw-?+rRmx zTBP|zt9fEFV`#>NSoReD~v;9>#;Q3nI(syiY!!IgjCA`U9`` zKUVW5e4G5G%Dr2T@$c;eM@!v=!bMQ(wwFWmUNVrVEN=jZBIBo^o!>KW+g=ISHsC@yg=E5Wa$IHa;5 zRX-@TIKQ+gIn}i+HLpY&*@%>6xc-9Dq8zYyQj+ykb5e6t^Gb^K4fPCBtaSJE4S?$a z1wnddZUIv!b%}i5`%}mX7&C|?NbWIE`4RkG1EKPMS&CHSvEfS55(u`7&jPlGY zE=kNwP6ZiNkz1gbnVDjhnv|SoV3};LYiVd?sB2niv`;>n0_qrs^gdnWv_hCYqQg zrlo?7N=deI%P-1JEU{I}%uP&B)i20P2TOng+{!V)(^kny&j2A3kds)FmS2=>tK^fJ zS6YFP2+7P%4K7Ipg{GmIg`v5TnT3U^p`oF=^oqawG!%DE^tu_V7JBtJjLRte-J1tUE}h;u;FzNsaNDTyVCE{P?n zwn|0@M#feKCRT>#A%;d)Mut{KrrHKZRt8Aw^HVa@Dha8!17!{yNR)eI7MJ7~Rf2^e zIVw1{5W<6Sb234y6%-V}nZhbD8RCWF#IjUKe8Z)ZGZORCQ&Vh}pve`cB@;_huuL^E zGc`?4)=f$^Pu4ZDuuRlVva~eUwX`%eG%!t0F}1L?1P2n_^y2)qlJdl&RLAtxyb@a_ z_srY^a9Am5fFnv1RdsnrDkv5VjEr>+Omr~=OdsM!8+}lj0rRnqK1P^86d)Bcc3cV& zu^<;WJ1!f2a7hO$^&kd3IUQ7 zkESlF1s4~hJC&N3VyjfHWN*j&{!Fdh=oJEjJRI=sgoka``jE6m4977@wC!2U={5o&Y(9qi0*m&^9 zE-~jv=OzWsivAZkvA>aX`Vuc6^H`^b&cp^rZk-($YkTy$nD$l&{CK^6T7VqWkzI&*%#gpvJzrSpuhw@*u0QdbkH|KqoN+pO~bjQes2rV3my`ebZS z@G1B@Od&M7&IR5@SI3Y#qq{4^C!p(Q~ z?=LV-l%H=nM>I68sTE(f8=ReHoo&Atg*!Zxto+BHh z3Oi4QUc_1bqY0mW@g2UzEiDmoQO2!ge?!>ZU@?j01q=+6qE`t&XOOuHN&ud&elF{r G5}E)c+pBs2 literal 0 HcmV?d00001 diff --git a/src/app.rs b/src/app.rs index 2357f3e..d5f17dd 100644 --- a/src/app.rs +++ b/src/app.rs @@ -23,6 +23,7 @@ use crate::{ inventory::{ItemId, Slot, TileLayer, UseAction}, math::{center_offset, TILE_SIZE}, res::Res, + tiles::TileId, CliArgs, }; @@ -158,9 +159,12 @@ impl App { .clamp(-terminal_velocity, terminal_velocity); let mut on_screen_tile_ents = Vec::new(); for_each_tile_on_screen(self.game.camera_offset, self.rt.size(), |tp, _sp| { - let tid = self.game.world.tile_at_mut(tp, &self.game.worldgen).mid; - let tdef = &self.game.tile_db[tid]; - let Some(bb) = tdef.bb else { + let tile = self.game.world.tile_at_mut(tp, &self.game.worldgen).mid; + if tile.empty() { + return; + } + let tdef = &self.game.tile_db[tile]; + let Some(bb) = tdef.layer.bb else { return; }; let x = tp.x as i32 * TILE_SIZE as i32; @@ -173,7 +177,7 @@ impl App { ); on_screen_tile_ents.push(TileColEn { col: en, - platform: tdef.platform, + platform: tdef.layer.platform, }); }); imm_dbg!(on_screen_tile_ents.len()); @@ -264,27 +268,25 @@ impl App { let def = &self.game.itemdb.db[active_slot.id as usize]; let t = self.game.world.tile_at_mut(mouse_tpos, &self.game.worldgen); match &def.use_action { - UseAction::PlaceTile { layer, id } => match layer { - TileLayer::Bg => { - if t.bg == 0 { - t.bg = *id - } + UseAction::PlaceBgTile { id } => { + if t.bg.empty() { + t.bg = *id } - TileLayer::Mid => { - if t.mid == 0 { - t.mid = *id - } + } + UseAction::PlaceMidTile { id } => { + if t.mid.empty() { + t.mid = *id } - TileLayer::Fg => { - if t.fg == 0 { - t.fg = *id - } + } + UseAction::PlaceFgTile { id } => { + if t.fg.empty() { + t.fg = *id } - }, + } UseAction::RemoveTile { layer } => match layer { - TileLayer::Bg => t.bg = 0, - TileLayer::Mid => t.mid = 0, - TileLayer::Fg => t.fg = 0, + TileLayer::Bg => t.bg = TileId::EMPTY, + TileLayer::Mid => t.mid = TileId::EMPTY, + TileLayer::Fg => t.fg = TileId::EMPTY, }, } } diff --git a/src/game.rs b/src/game.rs index 5d39a50..8a69efd 100644 --- a/src/game.rs +++ b/src/game.rs @@ -17,7 +17,7 @@ use crate::{ math::{smoothwave, wp_to_tp, WorldPos}, res::Res, tiles::TileDb, - world::{Tile, TilePos, World}, + world::{TilePos, World}, worldgen::Worldgen, }; @@ -77,11 +77,11 @@ impl GameState { for_each_tile_on_screen(self.camera_offset, rt.size(), |tp, sp| { let tile = self.world.tile_at_mut(tp, &self.worldgen); s.set_position(sp.to_sf_vec()); - if tile.bg != Tile::EMPTY { + if !tile.bg.empty() { s.set_texture_rect(self.tile_db[tile.bg].tex_rect.to_sf()); rt.draw(&s); } - if tile.mid != Tile::EMPTY { + if !tile.mid.empty() { s.set_texture_rect(self.tile_db[tile.mid].tex_rect.to_sf()); if let Some(light) = self.tile_db[tile.mid].light { let pos = ScreenVec { @@ -92,7 +92,7 @@ impl GameState { } rt.draw(&s); } - if tile.fg != Tile::EMPTY { + if !tile.fg.empty() { s.set_texture_rect(self.tile_db[tile.fg].tex_rect.to_sf()); rt.draw(&s); } diff --git a/src/inventory.rs b/src/inventory.rs index 7c2f22e..6c4f841 100644 --- a/src/inventory.rs +++ b/src/inventory.rs @@ -1,6 +1,9 @@ use egui_inspect::derive::Inspect; -use crate::{math::IntRect, world::TileId}; +use crate::{ + math::IntRect, + tiles::{BgTileId, FgTileId, MidTileId}, +}; /// We won't have more than 65535 different items pub type ItemId = u16; @@ -63,7 +66,9 @@ pub enum TileLayer { #[derive(Debug)] pub enum UseAction { - PlaceTile { layer: TileLayer, id: TileId }, + PlaceBgTile { id: BgTileId }, + PlaceMidTile { id: MidTileId }, + PlaceFgTile { id: FgTileId }, RemoveTile { layer: TileLayer }, } @@ -80,9 +85,8 @@ impl Default for ItemDb { name: String::from("Dirt Block"), graphic_name: String::from("tiles/dirt"), tex_rect: IntRect::default(), - use_action: UseAction::PlaceTile { - layer: TileLayer::Mid, - id: 3, + use_action: UseAction::PlaceMidTile { + id: MidTileId::DIRT, }, consumable: true, }, @@ -90,9 +94,8 @@ impl Default for ItemDb { name: String::from("Torch"), graphic_name: String::from("tiles/torch"), tex_rect: IntRect::default(), - use_action: UseAction::PlaceTile { - layer: TileLayer::Mid, - id: 4, + use_action: UseAction::PlaceMidTile { + id: MidTileId::TORCH, }, consumable: true, }, @@ -100,9 +103,8 @@ impl Default for ItemDb { name: String::from("Platform"), graphic_name: String::from("tiles/platform"), tex_rect: IntRect::default(), - use_action: UseAction::PlaceTile { - layer: TileLayer::Mid, - id: 5, + use_action: UseAction::PlaceMidTile { + id: MidTileId::PLATFORM, }, consumable: true, }, @@ -119,9 +121,8 @@ impl Default for ItemDb { name: String::from("Panzerium"), graphic_name: String::from("tiles/panzerium"), tex_rect: IntRect::default(), - use_action: UseAction::PlaceTile { - layer: TileLayer::Mid, - id: 6, + use_action: UseAction::PlaceMidTile { + id: MidTileId::PANZERIUM, }, consumable: true, }, diff --git a/src/tiles.rs b/src/tiles.rs index fbdbd26..4b6288e 100644 --- a/src/tiles.rs +++ b/src/tiles.rs @@ -1,26 +1,186 @@ pub mod tiledb_edit_ui; -use std::ops::Index; +use std::{fmt::Debug, marker::PhantomData, ops::Index}; -use egui_inspect::derive::Inspect; +use egui_inspect::{derive::Inspect, Inspect}; use serde::{Deserialize, Serialize}; use crate::{ - graphics::{ScreenSc, ScreenVec}, + graphics::ScreenVec, math::{IntRect, TILE_SIZE}, texture_atlas::RectMap, - world::TileId, }; -#[derive(Serialize, Deserialize, Default, Debug, Inspect)] -pub struct TileDef { - pub bb: Option, +#[derive(Inspect, PartialEq, Eq)] +pub struct TileId(pub u16, PhantomData); + +impl Copy for TileId {} +impl Clone for TileId { + fn clone(&self) -> Self { + Self(self.0, PhantomData) + } +} +impl Debug for TileId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("TileId").field(&self.0).finish() + } +} + +impl TileId { + pub fn empty(&self) -> bool { + self.0 == 0 + } + pub const EMPTY: Self = Self(0, PhantomData); +} + +#[derive(Debug)] +pub enum Bg {} +#[derive(Debug)] +pub enum Mid {} +#[derive(Debug)] +pub enum Fg {} + +impl Bg { + pub fn unknown_def() -> TileDef { + TileDef { + light: Some(ScreenVec { x: 0, y: 0 }), + graphic_name: String::from("tiles/unknown_bg"), + tex_rect: IntRect { + x: 0, + y: 0, + w: 0, + h: 0, + }, + layer: (), + } + } +} + +impl Mid { + pub fn unknown_def() -> TileDef { + TileDef { + light: Some(ScreenVec { x: 0, y: 0 }), + graphic_name: String::from("tiles/unknown_mid"), + tex_rect: IntRect { + x: 0, + y: 0, + w: 0, + h: 0, + }, + layer: MidDef { + platform: true, + bb: Some(TileBb { + x: 0, + y: 0, + w: 32, + h: 32, + }), + }, + } + } +} + +impl Fg { + pub fn unknown_def() -> TileDef { + TileDef { + light: Some(ScreenVec { x: 0, y: 0 }), + graphic_name: String::from("tiles/unknown_fg"), + tex_rect: IntRect { + x: 0, + y: 0, + w: 0, + h: 0, + }, + layer: (), + } + } +} + +pub trait TileLayer { + /// Definitions specific to this layer + type SpecificDef; +} + +impl TileLayer for Bg { + type SpecificDef = (); +} + +impl TileLayer for Mid { + type SpecificDef = MidDef; +} + +impl TileLayer for Fg { + type SpecificDef = (); +} + +pub type BgTileId = TileId; +pub type MidTileId = TileId; +pub type FgTileId = TileId; + +impl BgTileId { + pub const DIRT: Self = Self(1, PhantomData); + pub const STONE: Self = Self(2, PhantomData); +} + +impl MidTileId { + pub const DIRT: Self = Self(1, PhantomData); + pub const STONE: Self = Self(2, PhantomData); + pub const TORCH: Self = Self(3, PhantomData); + pub const PLATFORM: Self = Self(4, PhantomData); + pub const PANZERIUM: Self = Self(5, PhantomData); + pub const UNBREAKANIUM: Self = Self(6, PhantomData); +} + +impl FgTileId { + pub const COAL: Self = Self(1, PhantomData); +} + +#[derive(Serialize, Deserialize, Inspect)] +pub struct TileDef +where + Layer::SpecificDef: Debug + Inspect, +{ /// Whether the tile emits light, and the light source offset pub light: Option, - /// Platform behavior: Horizontally passable, vertically passable upwards - pub platform: bool, pub graphic_name: String, pub tex_rect: IntRect, + pub layer: Layer::SpecificDef, +} + +#[derive(Debug, Inspect, Default, Serialize, Deserialize)] +pub struct MidDef { + /// Platform behavior: Horizontally passable, vertically passable upwards + pub platform: bool, + /// Collision bounding box + pub bb: Option, +} + +impl Debug for TileDef +where + Layer::SpecificDef: Debug + Inspect, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("TileDef") + .field("light", &self.light) + .field("graphic_name", &self.graphic_name) + .field("tex_rect", &self.tex_rect) + .field("layer", &self.layer) + .finish() + } +} + +impl Default for TileDef +where + Layer::SpecificDef: Default + Debug + Inspect, +{ + fn default() -> Self { + Self { + light: Default::default(), + graphic_name: Default::default(), + tex_rect: Default::default(), + layer: Layer::SpecificDef::default(), + } + } } const DEFAULT_TILE_BB: TileBb = TileBb { @@ -40,49 +200,54 @@ pub struct TileBb { #[derive(Serialize, Deserialize, Debug, Inspect)] pub struct TileDb { - db: Vec, + unknown_bg: TileDef, + unknown_mid: TileDef, + unknown_fg: TileDef, + bg: Vec>, + mid: Vec>, + fg: Vec>, } impl Default for TileDb { fn default() -> Self { - let unknown = TileDef { - bb: None, - light: Some(ScreenVec { - x: TILE_SIZE as ScreenSc / 2, - y: TILE_SIZE as ScreenSc / 2, - }), - platform: false, - graphic_name: String::from("tiles/unknown"), - tex_rect: IntRect::default(), - }; Self { - db: vec![EMPTY, unknown], + unknown_bg: Bg::unknown_def(), + unknown_mid: Mid::unknown_def(), + unknown_fg: Fg::unknown_def(), + bg: vec![], + mid: vec![], + fg: vec![], } } } -const EMPTY: TileDef = TileDef { - bb: None, - light: None, - // Rendering empty tile is actually special cased, and no rendering is done. - // But just in case, put the offset to UNKNOWN - tex_rect: IntRect { - x: 0, - y: 0, - w: 0, - h: 0, - }, - platform: false, - graphic_name: String::new(), -}; +impl Index for TileDb { + type Output = TileDef; -impl Index for TileDb { - type Output = TileDef; + fn index(&self, index: BgTileId) -> &Self::Output { + self.bg + .get(index.0 as usize - 1) + .unwrap_or(&self.unknown_bg) + } +} - fn index(&self, index: TileId) -> &Self::Output { - self.db.get(index as usize).unwrap_or_else(|| { - &self.db[1] // Unknown tile def is stored at index 1 - }) +impl Index for TileDb { + type Output = TileDef; + + fn index(&self, index: MidTileId) -> &Self::Output { + self.mid + .get(index.0 as usize - 1) + .unwrap_or(&self.unknown_mid) + } +} + +impl Index for TileDb { + type Output = TileDef; + + fn index(&self, index: FgTileId) -> &Self::Output { + self.fg + .get(index.0 as usize - 1) + .unwrap_or(&self.unknown_fg) } } @@ -115,14 +280,38 @@ impl TileDb { } pub(crate) fn update_rects(&mut self, rects: &RectMap) { - for def in &mut self.db { - if !def.graphic_name.is_empty() { - if let Some(rect) = rects.get(&def.graphic_name) { - def.tex_rect = *rect; - } else { - log::error!("Missing texture for {}", def.graphic_name); - } - } - } + update_rect_def(&mut self.unknown_bg, rects); + update_rect_def(&mut self.unknown_mid, rects); + update_rect_def(&mut self.unknown_fg, rects); + update_rect_db(&mut self.bg, rects); + update_rect_db(&mut self.mid, rects); + update_rect_db(&mut self.fg, rects); + } +} + +fn update_rect_db(db: &mut Vec>, rects: &RectMap) +where + Layer::SpecificDef: Debug + Inspect, +{ + for def in db { + update_rect_def(def, rects); + } +} + +fn update_rect_def( + def: &mut TileDef, + rects: &std::collections::HashMap, +) where + Layer::SpecificDef: Debug + Inspect, +{ + if !def.graphic_name.is_empty() { + if let Some(rect) = rects.get(def.graphic_name.as_str()) { + def.tex_rect = *rect; + log::info!("Updated rect for {}: {:?}", def.graphic_name.as_str(), rect); + } else { + log::error!("Missing texture for {:?}", def.graphic_name.as_str()); + } + } else { + log::warn!("Empty graphic name!"); } } diff --git a/src/tiles/tiledb_edit_ui.rs b/src/tiles/tiledb_edit_ui.rs index 634eded..6986541 100644 --- a/src/tiles/tiledb_edit_ui.rs +++ b/src/tiles/tiledb_edit_ui.rs @@ -1,57 +1,91 @@ +use std::fmt::Debug; + +use egui_inspect::Inspect; + use crate::{ graphics::{ScreenSc, ScreenVec}, math::TILE_SIZE, }; -use super::{TileDb, DEFAULT_TILE_BB}; +use super::{Bg, Fg, Mid, TileDb, TileDef, TileLayer, DEFAULT_TILE_BB}; pub fn tiledb_edit_ui(ctx: &egui::Context, tile_db: &mut TileDb) { egui::Window::new("Tiledb editor").show(ctx, |ui| { - ui.label(format!("Number of tile defs: {}", tile_db.db.len())); ui.separator(); egui::ScrollArea::vertical() .max_height(400.0) .show(ui, |ui| { - for (i, def) in tile_db.db.iter_mut().enumerate() { - ui.label(i.to_string()); - match &mut def.light { - Some(light) => { - ui.label("x"); - ui.add(egui::DragValue::new(&mut light.x)); - ui.label("y"); - ui.add(egui::DragValue::new(&mut light.y)); - } - None => { - if ui.button("Insert light emit").clicked() { - def.light = Some(ScreenVec { - x: TILE_SIZE as ScreenSc / 2, - y: TILE_SIZE as ScreenSc / 2, - }); - } - } - } - match &mut def.bb { - Some(bb) => { - ui.label("x"); - ui.add(egui::DragValue::new(&mut bb.x)); - ui.label("y"); - ui.add(egui::DragValue::new(&mut bb.y)); - ui.label("w"); - ui.add(egui::DragValue::new(&mut bb.w)); - ui.label("h"); - ui.add(egui::DragValue::new(&mut bb.h)); - } - None => { - if ui.button("Insert bb").clicked() { - def.bb = Some(DEFAULT_TILE_BB); - } - } - } - } + ui.heading("Bg"); + db_ui(&mut tile_db.bg, ui); + ui.heading("Mid"); + db_ui(&mut tile_db.mid, ui); + ui.heading("Fg"); + db_ui(&mut tile_db.fg, ui); }); - ui.separator(); - if ui.button("Add new default").clicked() { - tile_db.db.push(super::TileDef::default()); - } }); } + +trait SpecialUi { + fn special_ui(&mut self, ui: &mut egui::Ui); +} + +impl SpecialUi for TileDef { + fn special_ui(&mut self, ui: &mut egui::Ui) { + match &mut self.layer.bb { + Some(bb) => { + ui.label("x"); + ui.add(egui::DragValue::new(&mut bb.x)); + ui.label("y"); + ui.add(egui::DragValue::new(&mut bb.y)); + ui.label("w"); + ui.add(egui::DragValue::new(&mut bb.w)); + ui.label("h"); + ui.add(egui::DragValue::new(&mut bb.h)); + } + None => { + if ui.button("Insert bb").clicked() { + self.layer.bb = Some(DEFAULT_TILE_BB); + } + } + } + } +} + +impl SpecialUi for TileDef { + fn special_ui(&mut self, _ui: &mut egui::Ui) {} +} + +impl SpecialUi for TileDef { + fn special_ui(&mut self, _ui: &mut egui::Ui) {} +} + +fn db_ui(db: &mut Vec>, ui: &mut egui::Ui) +where + ::SpecificDef: Debug + Default + Inspect, + TileDef: SpecialUi, +{ + for (i, def) in db.iter_mut().enumerate() { + ui.label(i.to_string()); + match &mut def.light { + Some(light) => { + ui.label("x"); + ui.add(egui::DragValue::new(&mut light.x)); + ui.label("y"); + ui.add(egui::DragValue::new(&mut light.y)); + } + None => { + if ui.button("Insert light emit").clicked() { + def.light = Some(ScreenVec { + x: TILE_SIZE as ScreenSc / 2, + y: TILE_SIZE as ScreenSc / 2, + }); + } + } + } + def.special_ui(ui); + } + ui.separator(); + if ui.button("Add new default").clicked() { + db.push(Default::default()); + } +} diff --git a/src/world.rs b/src/world.rs index 8f4477b..9077106 100644 --- a/src/world.rs +++ b/src/world.rs @@ -13,7 +13,11 @@ use fnv::FnvHashMap; use serde::{Deserialize, Serialize}; use crate::{ - math::WorldPos, player::Player, world::reg_chunk_existence::ExistenceBitset, worldgen::Worldgen, + math::WorldPos, + player::Player, + tiles::{BgTileId, FgTileId, MidTileId, TileId}, + world::reg_chunk_existence::ExistenceBitset, + worldgen::Worldgen, }; use self::serialization::save_chunk; @@ -203,9 +207,9 @@ type ChunkTiles = [Tile; CHUNK_N_TILES]; fn default_chunk_tiles() -> ChunkTiles { [Tile { - bg: 0, - mid: 0, - fg: 0, + bg: TileId::EMPTY, + mid: TileId::EMPTY, + fg: TileId::EMPTY, }; CHUNK_N_TILES] } @@ -229,7 +233,7 @@ impl Chunk { // Unbreakable layer at bottom if pos.y > 798 { for b in &mut tiles { - b.mid = Tile::UNBREAKANIUM; + b.mid = MidTileId::UNBREAKANIUM; } } Self { tiles } @@ -269,21 +273,14 @@ fn chunk_exists(reg_path: &Path, pos: ChunkPos) -> bool { crate::bitmanip::nth_bit_set(bitset.0, idx as usize) } -pub type TileId = u16; - #[derive(Clone, Copy, Debug, Inspect)] pub struct Tile { /// Background wall behind entities - pub bg: TileId, + pub bg: BgTileId, /// The solid wall on the same level as entities - pub mid: TileId, + pub mid: MidTileId, /// A layer on top of the mid wall. Usually ores or decorative pieces. - pub fg: TileId, -} - -impl Tile { - pub const EMPTY: TileId = 0; - pub const UNBREAKANIUM: TileId = 5; + pub fg: FgTileId, } pub const REGION_CHUNK_EXTENT: u8 = 8; diff --git a/src/world/serialization.rs b/src/world/serialization.rs index 93c149b..065e2ed 100644 --- a/src/world/serialization.rs +++ b/src/world/serialization.rs @@ -42,9 +42,9 @@ pub(super) fn save_chunk(pos: &ChunkPos, chk: &Chunk, world_dir: &Path) { let byte_idx = loc_byte_idx(loc_idx); for (i, tile) in chk.tiles.iter().enumerate() { let off = byte_idx + (i * TILE_BYTES); - region_tile_data[off..off + 2].copy_from_slice(&tile.bg.to_le_bytes()); - region_tile_data[off + 2..off + 4].copy_from_slice(&tile.mid.to_le_bytes()); - region_tile_data[off + 4..off + 6].copy_from_slice(&tile.fg.to_le_bytes()); + region_tile_data[off..off + 2].copy_from_slice(&tile.bg.0.to_le_bytes()); + region_tile_data[off + 2..off + 4].copy_from_slice(&tile.mid.0.to_le_bytes()); + region_tile_data[off + 4..off + 6].copy_from_slice(&tile.fg.0.to_le_bytes()); } f.rewind().unwrap(); f.write_all(&u64::to_le_bytes(existence_bitset.0)[..]) @@ -65,9 +65,9 @@ impl Chunk { let mut tiles = default_chunk_tiles(); for (i, t) in tiles.iter_mut().enumerate() { let off = byte_idx + (i * TILE_BYTES); - t.bg = u16::from_le_bytes(data[off..off + 2].try_into().unwrap()); - t.mid = u16::from_le_bytes(data[off + 2..off + 4].try_into().unwrap()); - t.fg = u16::from_le_bytes(data[off + 4..off + 6].try_into().unwrap()); + t.bg.0 = u16::from_le_bytes(data[off..off + 2].try_into().unwrap()); + t.mid.0 = u16::from_le_bytes(data[off + 2..off + 4].try_into().unwrap()); + t.fg.0 = u16::from_le_bytes(data[off + 4..off + 6].try_into().unwrap()); } Self { tiles } } @@ -83,7 +83,7 @@ fn test_chunk_seri() { tiles: super::default_chunk_tiles(), }; for t in &mut chk.tiles { - t.bg = 1; + t.bg = crate::tiles::BgTileId::DIRT; } save_chunk(&ChunkPos { x: 2, y: 0 }, &chk, "testworld".as_ref()); save_chunk(&ChunkPos { x: 3, y: 0 }, &chk, "testworld".as_ref()); diff --git a/src/worldgen.rs b/src/worldgen.rs index 97ad339..9ac53b3 100644 --- a/src/worldgen.rs +++ b/src/worldgen.rs @@ -8,7 +8,10 @@ use worldgen::{ }, }; -use crate::world::{ChunkPos, Tile as Tl, CHUNK_EXTENT}; +use crate::{ + tiles::{BgTileId, FgTileId, MidTileId, TileId}, + world::{ChunkPos, Tile as Tl, CHUNK_EXTENT}, +}; pub struct Worldgen { world: World, @@ -33,35 +36,35 @@ impl Worldgen { // Dirt coal .add( Tile::new(Tl { - bg: 9, - mid: 3, - fg: 6, + bg: BgTileId::DIRT, + mid: MidTileId::DIRT, + fg: FgTileId::COAL, }) .when(constraint!(nm.clone(), < -0.8)), ) // Dirt .add( Tile::new(Tl { - bg: 9, - mid: 3, - fg: 0, + bg: BgTileId::DIRT, + mid: MidTileId::DIRT, + fg: TileId::EMPTY, }) .when(constraint!(nm.clone(), < -0.1)), ) // Stone .add( Tile::new(Tl { - bg: 7, - mid: 2, - fg: 0, + bg: BgTileId::STONE, + mid: MidTileId::STONE, + fg: TileId::EMPTY, }) .when(constraint!(nm, < 0.45)), ) // Dirt wall .add(Tile::new(Tl { - bg: 9, - mid: 0, - fg: 0, + bg: BgTileId::DIRT, + mid: TileId::EMPTY, + fg: TileId::EMPTY, })); Self { world } } diff --git a/tiles.dat b/tiles.dat index 63551ed02365d7fa691110711953868253df601d..6b55e19f2566fcb80e702efd518b4d23c2c88fe4 100644 GIT binary patch literal 204 zcmbO>WfB9!hLX&j)MEY8yzIRE^1S$@^eJZ<8yFN64uB*#qDtmwrc61@=)j<$FzN6V z1_lKMkQy`t(m)0%fDD*4<-j_K{*=t3lBC4s>?vm%GZa8ZA6O5OC@#s*ONGijU{g>y kFlowxRS+qVo+)P;6F`<7f>?H7HAD)mYsy*10|>bZ03MD|OaK4? literal 237 zcmbO@YwCdmhZam>U|?XFdSH@(z@fDznK`M&`lWfzpNi0drFUp;Ama&0BfeqxK^-!6_ysFfq%u=wFLVPTe6xaz#iOJbh&N40lTZZt) RfkRM}L5_i{xzC`W006=6VSxYu