From 7cbb50e226177c10bfcc2983d3d4dd1bc1dd152e Mon Sep 17 00:00:00 2001 From: TheK0tYaRa Date: Mon, 16 Jun 2025 21:17:29 +0300 Subject: [PATCH 1/2] the world now generates. but the tiles are empty --- src/Game1.cs | 7 ++- src/src/World.cs | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 src/src/World.cs diff --git a/src/Game1.cs b/src/Game1.cs index 061b2b7..00f6c75 100644 --- a/src/Game1.cs +++ b/src/Game1.cs @@ -1,13 +1,15 @@ -using Microsoft.Xna.Framework; +using System.Collections.Generic; +using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; - +using World; namespace tunnet; public class Game1 : Game { private GraphicsDeviceManager _graphics; private SpriteBatch _spriteBatch; + private Dictionary _chunks; public Game1() { @@ -19,6 +21,7 @@ public class Game1 : Game protected override void Initialize() { // TODO: Add your initialization logic here + _chunks = new Dictionary(); base.Initialize(); } diff --git a/src/src/World.cs b/src/src/World.cs new file mode 100644 index 0000000..65ea2ed --- /dev/null +++ b/src/src/World.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using System.IO; +using Microsoft.Xna.Framework; +// +namespace World; + +public class Tile +{ + public int Id { get; } + public Tile(int id) => Id = id; + public static Tile FromId(int id) => new Tile(id); +} +public class Chunk +{ + public const int Width = 16; + public const int Height = 16; + public Tile[,] Tiles { get; private set; } + + public Chunk() + { + Tiles = new Tile[Width, Height]; + } +} + +public static class ChunkStorage +{ + /// + /// Saves the given chunk to disk in a compact binary format: + /// Width×Height consecutive Int32 tile IDs. + /// + public static void Save(string filePath, Chunk chunk) + { + if (chunk == null) + throw new System.ArgumentNullException(nameof(chunk)); + + Directory.CreateDirectory(Path.GetDirectoryName(filePath) ?? "."); + using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write); + using var writer = new BinaryWriter(fs); + + for (int x = 0; x < Chunk.Width; x++) + { + for (int y = 0; y < Chunk.Height; y++) + { + // write each tile’s ID + writer.Write(chunk.Tiles[x, y]?.Id ?? 0); + } + } + } + public static void Save(int chunkX, int chunkY, Chunk chunk) + { + Save($"{chunkX}_{chunkY}.chunk", chunk); + } + + /// + /// Loads a chunk from the binary file format produced by Save(). + /// + public static Chunk Load(string filePath) + { + if (!File.Exists(filePath)) + throw new FileNotFoundException("Chunk file not found", filePath); + + var chunk = new Chunk(); + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); + using var reader = new BinaryReader(fs); + + for (int x = 0; x < Chunk.Width; x++) + for (int y = 0; y < Chunk.Height; y++) + { + int id = reader.ReadInt32(); + chunk.Tiles[x, y] = Tile.FromId(id); + } + + return chunk; + } + public static Chunk Load(int chunkX, int chunkY) + { + var filePath = $"{chunkX}_{chunkY}.chunk"; + if (File.Exists(filePath)) + return Load(filePath); + return null; + } +} +public class WorldMap +{ + private readonly Dictionary _loadedChunks = new Dictionary(); + + // Get a chunk (load if not in memory) + public Chunk GetChunk(int chunkX, int chunkY) + { + var key = new Point(chunkX, chunkY); + if (!_loadedChunks.TryGetValue(key, out Chunk chunk)) + { + chunk = ChunkStorage.Load(chunkX, chunkY);// LoadChunkFromDisk(chunkX, chunkY); // Or generate + _loadedChunks[key] = chunk; + } + return chunk; + } + + // Access a specific tile + public Tile GetTile(int worldX, int worldY) + { + int chunkX = worldX / Chunk.Width; + int chunkY = worldY / Chunk.Height; + int tileX = worldX % Chunk.Width; + int tileY = worldY % Chunk.Height; + + // Handle negative coordinates + if (tileX < 0) tileX += Chunk.Width; + if (tileY < 0) tileY += Chunk.Height; + + return GetChunk(chunkX, chunkY).Tiles[tileX, tileY]; + } + + // Unload distant chunks (memory management) + public void UnloadChunks(Point currentChunk, int keepRadius) + { + var keysToRemove = new List(); + foreach (var key in _loadedChunks.Keys) + { + if (System.Math.Abs(key.X - currentChunk.X) > keepRadius || + System.Math.Abs(key.Y - currentChunk.Y) > keepRadius) + { + ChunkStorage.Save(key.X, key.Y, _loadedChunks[key]); // Persist if needed + keysToRemove.Add(key); + } + } + keysToRemove.ForEach(k => _loadedChunks.Remove(k)); + } +} \ No newline at end of file From bb4a48c3211609aebf3ef807f33a44f228e850b2 Mon Sep 17 00:00:00 2001 From: TheK0tYaRa Date: Tue, 17 Jun 2025 07:09:41 +0300 Subject: [PATCH 2/2] uhhhhhhhhhh --- .gitignore | 4 +- {src/Content => Content}/Content.mgcb | 12 ++ Content/Tilemap.kra | Bin 0 -> 23854 bytes Content/Tilemap.kra~ | Bin 0 -> 20637 bytes Content/Tilemap.png | Bin 0 -> 494 bytes src/Game1.cs => Game1.cs | 20 ++- src/Icon.bmp => Icon.bmp | Bin src/Icon.ico => Icon.ico | Bin src/Program.cs => Program.cs | 0 World/World.cs | 186 ++++++++++++++++++++++++++ src/app.manifest => app.manifest | 0 run.sh | 2 +- src/src/World.cs | 129 ------------------ src/tunnet.csproj => tunnet.csproj | 0 tunnet.sln | 2 +- 15 files changed, 219 insertions(+), 136 deletions(-) rename {src/Content => Content}/Content.mgcb (50%) create mode 100644 Content/Tilemap.kra create mode 100644 Content/Tilemap.kra~ create mode 100644 Content/Tilemap.png rename src/Game1.cs => Game1.cs (69%) rename src/Icon.bmp => Icon.bmp (100%) rename src/Icon.ico => Icon.ico (100%) rename src/Program.cs => Program.cs (100%) create mode 100644 World/World.cs rename src/app.manifest => app.manifest (100%) delete mode 100644 src/src/World.cs rename src/tunnet.csproj => tunnet.csproj (100%) diff --git a/.gitignore b/.gitignore index fea8d3f..fa6f4c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .config/ .vscode/ -src/bin -src/**/obj \ No newline at end of file +**/bin/ +**/obj/ \ No newline at end of file diff --git a/src/Content/Content.mgcb b/Content/Content.mgcb similarity index 50% rename from src/Content/Content.mgcb rename to Content/Content.mgcb index ddc4c36..e1a4b9c 100644 --- a/src/Content/Content.mgcb +++ b/Content/Content.mgcb @@ -13,3 +13,15 @@ #---------------------------------- Content ---------------------------------# +#begin Tilemap.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Tilemap.png + diff --git a/Content/Tilemap.kra b/Content/Tilemap.kra new file mode 100644 index 0000000000000000000000000000000000000000..11da0a87141343eedad2f0543fa3d8b66b705c99 GIT binary patch literal 23854 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 ZzumPpRS=+*FaQJcl?Is!p+?ZX{{v-VxXJ(k literal 0 HcmV?d00001 diff --git a/Content/Tilemap.kra~ b/Content/Tilemap.kra~ new file mode 100644 index 0000000000000000000000000000000000000000..e1e7c665f756b3559ced37e6221f272a0f7cffd4 GIT binary patch literal 20637 zcmeI4bx>T}`lcHV?(Po3I=H*LLx2Qmpm7VX!GZ;McTbQ&aCZrA3GS}JJxu4^I=^$z zxpQac?Qz;MfkguR-aMEm^m2c~6k|hqkI(EcKf<@-HV#OGBUfq za9NDb;fhH+*ng`OH=OKL_jMC)XoFME?pLD`zW&KUd)(&fDO-~G%lX%s#Lb8{lhtZu z#qaip!UuB@ij)d#Hh$)zHI*OV4~ zQxel1hohYbudV-;E{J3?dEo#dv1?a2I%BDA)4_;j zmREr*hv`=k=Bf>_rV5XeNGj?mQ0r^blRdop<>(~@S0^=ZBNPHcJNzlB0v~}ZPcq)* z;MHP|hASUU`@;SjK`|ZcF;^O`mf}bsVfMWWZHQqiK}AS+RfK#Gr)PSU&V+k|JoUSm z6@5Azr=FT-PtfuDxm=9kO}p}*zMyqkuTQG6(rARQ@&_&IsYfV<5S1OKe$C_7BCyRC zbKAf(rv%r${31~-v;b@QX`c7Y!U}DER-VBKL`FKDlt|tyU#5C#AU}P)Yi~t4NZuvM z>Ms2 zx~kY{SJz_lF8cP1q;;sf6w z2Xbva!NKj{dA?LSEvbj8R5&H{)%8DswN9R_BF786Dlf3TSOp1oIy5q_%S|yy$2jgM z7QR-8m}ISBg#|An+VYy-HVBQ)mGoOn%vav$Up>9UN6sDha$ai3%be4n0|pg+I#Q^g zng57X{8J)KI6tG!j!{d42K(T7Er8oY-`BVP7`Dm^x z2=NSPm^wkML7(u}_}hC$x~+*~!Vf{IB0?3arQsFZ-;8tXh=eM99~<@a2;pxs%K_Db z0!}n)&|jLebLT$Sj*#S>+?N=sfBg1EHvQXH2h9t5HLS$Cj0rzQa<9rlEBrOzcAQB7 zX5B<)A(VIz5)yf)%9#N5nRgPWD zrOc5_X4gZ_VaC%_6w2}QoG&aW(}%Qg!ByS3*Ly)mkh=hN8EI-ha0~ftnrY7bAXZ>b zh%~wNNnr(JnH<(%ZudgE-k3KE^RB7ME@i&a3g*lSZ6kJ%ZE_Xn?@v>pE)W<2d5X)B z_`RYzID%a*!EUS$cIF2tKb>~A;?|9gj8-o%91tOUQzIiI)m0-CBcq#U$2n|xc=%E1 z=mBGR_%>>aVP36tl{9~UP(X3GiEM91y$*o~F$zHnI=AwpZX0d9nq${WqmotIQ(m<# zIWkT*)8YL6QXbc@m6Ivoc1OW4X2!AwsCo}+E_>{(#C17}Ofly|Zy(=$=cDC>0{p$x zqB3I+LXgh#LIM{OnwB$%DW@oINQlC%3<&} zu5mNNX;jxS#$k|;nnG6$Cy_)dfhGVNI*)+@$xKpJOiEP^3PxH~ZFA^ z&;mrcJG-Zl0Us`+$!>tfPu&tvTc4hO!s?h~127Z-y9MJUn_yU}61sx?$0=>qP{e2uJck5!%5aaUnWoJrZ&jO`0JKa(QVg;}rKg>) zuqPU#U)iHKUY;4ar;x@AGIPqjzve8KB#(gyGfqR2&ox`x6fF&A#!Wf*a zu7dO)X_@{$n#stxIIJ$1`1mdplg&3>&{!$bYHP8IO&?pRd{h+Q*ob3sq}bh8BEQ|w zmd38d#R>Q|M7wKHRy>ku>>Q9HJKnMhpMs!qZb7=6zL31sh(c+0K);3}HhMwg zhwT7E)`5Hj5W#>I_e1;O&wv55E($FR1s?;?E{Zk)1DAu4;E$vVXC(?_0nL(w>g-20 z{sO)Og8&BG2x-_4?hCAT2hl9FfD!udTJWqLxQ9^39Wd_Dz*QJ;fAXI%peQh4{f#i7 z#l;8^Uc^!$Nd^*NAg_x-%fiZ0z!d~=#-Oo_(hWf0i=hp`c~Fq!1i-9PFhKX_z>>hr zh`!{7j|ya0MPn4hErI9CL7NVQA4f>*kQ+x)_QxAXnimz=1!S%=??NxF3hqL+=Ad5$ zLcKy@4NzERCxF-KKp=oKStTNP!P5bo0?X5B>+oU`?z#iV9Z=LM@d}yDzuyRLIIwt? z@HGI~LFJBU;QwP4)g5`+U+W9}a$xi-_6p(slB>Q;pb4)fs-?=M zi990_sfs;~k{PU*>$;2LjJF>!Dkh{#K8=nlE-?kBlBf^)YrMQr%E20I&b-*m=sR7vKcN~BSpB0r`d8T-uquKN zR^b~E?Sl1Jxo=Rs@q}Moci^u=xg(GTS9Y2F>Z2?LiX>jFOag|M zB+P{L1qMtH0h%2#Mbl804hYjA4~m_|h!-Hd z6qAqLkcCqZoTjFaF)M(xl;MxHD|pf9heDMc!!*Fa9;HZ8AL}&$V+!vPF-$!cOS{Q+ zhNmkfOmQ&4V+wN{_8|Q$&j^PoNCHz$69=`|e_i@C|AQ(O!#f-p+HiHz(wu2EJqDo! z%5Sh>|7z*E+zizU2Db#BZ|Jz8#(7<;Y9+5VsTkoBqrQo6hfR2wS6o%WjM-zT<$xkRoF zgtx#U3Zcs@wczHYPs3*k#S;t9C$!+J!P3Jm5Bn}foToI7XF*&8Gf#LFd?kLL3o}8v z>)_1EPnH>>EMuPQGy%6ubpg6ybB1ezU-Ac$p`=+)CrO$z(WxTChm^L>Am z8D{%V;1z+~N4gPt+7AordZm`atB6HM8Xq*+i(`xil4k>_SSbn>Ax;JCbvT1O* zQZR>k&9I#C&jIHM9MQTREnO|WE&XLCZJ@eW?NxyAuJtNYX4Ijut!^Yx?-%vgd}UbL zq@N?XI?{|-s$5^wml1zQK8Qx`3I^p@ozCLez;hGp`?2(qbtZv6S6$A=&uSkM9`YT+ z9ZDVI9&#PhT%lb-U146myn?&pa)rCcyvJ?!U+OzvSLGFqipXDUaCqPaWxy)K7yD`S zTCQEZqvKV`ARQ&#i8}9uTNQVRZQy;wZb!~atmDVjm$?4z9an?&;>$Mz705rriF;5t z`W&zu1R7p6$TSo;&@K`$64{YnlU`%j2g*R^0ijB_(;D1QDtEaSW&^}Z{~x`?Ya^$1 z?({9h%f#e<=$$g_8>cTJQ;78!pbgfS#4xC`pJ!v?r}=5?jo1V31J?u1FS1{h@6p=* zd?O7zeYAqmPBLu**K?mlDs?u6uqac{US_e>fMy@I$P<+71LqPnX zDUL^(tt!bttBGNSsPsWwoIW??m287}gLH#jgGvhRFg6~dJ;DiMHX`wd70J+0+PF|o zDju~M2I&MkMvR$Ieo5*)xQVD;@e7(e?7%S09$sT4w)hkoW~wACrcjrj_#SR!{HkbP zNfOFsie*Y=>}(AD(8@6Dp0OU(b$cwyuDAgjZY=aL;q?-zkaXSq9NIg-ppEDflu-6qG5=eIW~(oY0m`CWX{~qxZ(1QUg99V2#Tf>2dUyP?BfW1eA%0}E_s@Bqan_qmLT~} zSe~^oR9(KbfKydjga2hKWTqp41018-6+EOpq;w0ti)_?gOBfhq<@3)}_cY}`32H@t zQsBzf)5t6#)AY4M;7UuA9Ld>M3oq?2;hLtiBCbuJS0OEm(l}8iSKldBn0A|1nMU0w z$NLb}A#Sn;%Ka)^&G4n<>uyy_^=x&+7xyaI>JMLgstT%1zmgce1ecmxnp%SRh8+F3 z*oSzBY?CaLJd$XWaFbk;l#)obIhn!|GZUk=6138^QnkWoLTBP;VrMdEvbhqtg1LgY z!fRtL5v<{?VXTo4biX5)b(d|FxxF@jon75#{MO{L>nxGS70bhFK5l=v8^ZcTwwHmx((|9Sa_dYl~=$G0UME^qP~J6&nQN*vQDp zXr%;pt5SA2{k1Sy<@#TI;uk_*csr8xkc@_W*T6KtZ_ckiCcyr5D z9kE%`PN)O*0I=jAfm2y>brFLaG;SThMihAUvJ#>RgHu>#PQDY!ST}a;_`CwqVkpVX7aW22J+_f#`9e} zk*x}T)9s!co*VS=cS<>j-|-ox&rrztoMFgU--yAAg)fi{NQO;@PNqx7Oy){PPDaO% zX9{LYWD5D5@;TzO|L4R5k{?nPY!wS{INppkE<5Py116Q<_oePbE$z zRwaEbVJvGb5Euje2uua0SEf{ERK`|jRwmo0*aw_It!T7?+f=;uA238>vjYu7vpXxh zD*Np_PkK&9#x|ojR{9M)48Iw6`+jT>_lk1PMR~cg&_=fon zv*nhRG(%ewD2s zh#7E+eL*!Qxg6$=drSQh8;p&Mm58T>&4pEqdx?RH6^Xkhhm>zvZtv@!o8E#R%^s8Dc;s`uGcY z{h?DmaJ_`1ZZ`UQ(d3uU_@q2W7+QU!eF=!iTBx!MI zoN1V8-q1YIQqii@BGE+2amqT&UMNJ!EykxLyHlS^8OvY+2Pt1NzoajvwPf96-lHd^ zOr=T%dT3S~RKKk@bW}Xc+SC}Vk29ooD?m`sP|s6GQs-AsQm;_=D$FaKEJTw{l*^3a zXL3>751y`>MlR(lRe~SRVZR|zN6`w#?2cONMF7*VI}(Ht)<$qklba;Gi)I^hAG-N= z!=#k3orD*!9rr!CF3B|+Eh#E_G)|c2Ez1(s5|fYCUDQR!1@T_xq%RnO{SCV@yFB|H zJ2yKSyJ9MAs!eJ)do6o8yAOLl`?YD-x0d)@R^&l-(_7O*(;3r9FsZ4JX*XEI^c);L zm=z<$BtRoTDL~y!b1&zrkH*x`O3z$OQOsmcyF-W1j1R0gtdOkGu24D-SmbJa*|_6q z?U;VX;Gyjy=ArAs;(_d;a|^hAeXDpYaW->Se&%y#a(2CyJyiM4o{<8n3@HGq8fhL0 z56KG$8h0J%iYb9%nz4rIf+>PYk*P)XCg-ODX8u40LtaTvNwG!#ZYja1l!BCEcg52W z#>wlnz3CsLag%Y|8IKub6WtRF5~dRs6EhO87<(DOjHK$H)T}i2b%=D*wDmOaN@~g@ zG`2PIG_Ue10ww(o>d2MAg65zVxs^QY&!r%(vk|!c0 zawftsCNdUld201(7HQ&X3YR>n_kMEx^s)3)2~jD3$z7>*saXl$=kFzTrD!DvI+f2hr{&AgjHoRk|MoZ_pPDx1pZDB>vpT5ztrQ^_i&qpG82CrQk)^#pK1u3#*IyOV<6R>GUc6iG|7j zeWyKzed}HQ-R6Uk{o;M{>B{f+KiW%tHGGwQrF@3~)*WC9%N&pqXw?qGD#lFJRMli0 z^vcv>XtlI6trIBGLK&S~lUtWto0|+O00o1>K!Kp-HQes|U?7SJ;V-T{0z{&h1cU^9 z1V>ySIlgi6+c|$L8QX1|D4QV8C-1W`K{G)#aWO$Qaoc#c!MS0)!M~xr0orKpL+;Ct za8qQU6Q@I>3#L=1gQ7#EyQRaWW1)kgi>Gs}>Q_ux zx>xL1GFMtju}c9BHw+gH*9@19w2b5pR}agNqz!uxSEP=lu%th}l1X<;RYDY7v#M5#e3cmy+@ zF5MvgfIHe&+vfcomd&m0mMyAnrfs0DhE2H5flafGj7_nv;li&k-Lt2&gR^^ce6w(~ zwDY+0S__#~&Bi?7>&fGEp>J73S)fW2d-D_fY$HP>L$Gh(``KS@k8zJYFA`viVYz_~bJBCV+fa1Dd#CME=Wyj1H+K`Xy|#wA6}zE!JaPPP z&g9!hZGSNRvPOr-#MJauH^(H$!q>&GOXt-)2|LzfO2C$6zvQ^&)Z}8F1f3|IAf1pO zxRsWbJO(1IVawvnjLUe-%ga^Ex63oj=B+ZV=B+v{zW1s=l0KZ?Hr`ivG`BdnoHrLY zi$7DZZ+DSz9dFpZFTFFpQ`_#n6?{}~(e9Qn-<~}lhn#O*Yg}+#o?nDt4V`~JJGdae zOuy7Wz26vH2Od{$*`JW_X73xW`%bp6Jk>oRKiPY+dEH(y9&#-mRPlJ)FE4*;HNTEJ z_Nj5RJy8a*h_Z{)cd+>pegWoit~z(9c0Bs&K&AWlhuBt{;XYcy(rCv-?9A_s4)_u9 z#6FjTQY1VTMA$cMoWvoJqLa!othKF-z#_>m3GCsc;iO?IU@j2av>H$xuo_TiV9{jM z1Wwa(GCTWPc@c9x5!>tS8OC`J4ngMJc!o_ z(TG5VN>mYYVa#8G4+^k!0V3jjUF=;vRBU;?c`uDA)|GpPLPuoP3uFt-3Vci*HrobF zVr^q}sLZK!sGp>(WaMNBr5mNBq_(7HBs0UCFfW<+6*%eAMD%Fq8Rtd#`I=~&_&gar z8Sj)XTv4neOd|{;6ci;Dl@+xV-G(nyirEZ}*{U9@7^}3ayi7EV(fhNaT5$wO?^#{x zqga&rM_-K!vGP|?RIpa?9Gfi~FGjl?x5&1bwMcl&dYgHBc$+`Get7fX3C-va6yxh; z?-Ze=U6U18=-T=ag7_J+IV>ZrI*cyNAnY_uDoiOXFzgz8g~pD)icXG}kfxDViXN9{ zhW?UvN!c^CCQ(r?N%p&ft5THWr~>3IK&~ydC8Z@*Tp3egLhhY%nCzfZsT^OnBL|ob zOr4m(nDi-rKZ7VXEnP2uKHihVh0TQ{GJ`IwD1AE(FEuGyJNbLMtH2R>e$3gb$+YQx zlRo6HVUVYZr|(_s#n#2j{p^+83CHqIE%3eJY1_7s#C_3qxtSkI1xgS~ILcE*Ld0Z5 zT|{gIJ>fy>uA;wUtzxsHnVGg3*vxHPa$9^mnpr*Rb&_3@wYH|Vn6`wr@At>DdR>8g zzN?`lo`sWU5s#k185_oqZOmagKdeA?Dslo)@aoI4E;>> zlsl@Udl_pPGJNDtYK_p1R*hGUl#O$ZGmS!x^^S&HzrN*f$?c?WdhF0{k&arA5D$9A zUGtHrtBn2l=JqXmU~H^%>}0Gx`-%I>9!kgG*dHt=+SwLx7ElpD3LC(f`FYG5k;VpXaH{@Re6ZArvq`}?ju47*8hGIo*CeZbT1o}2fnb54; z&*M&>7j7RLKH`LzeS{8Y|Hv3Vio3+@sax}QSesej#^BH}L)*LM#^y9~y?4D_f;prB zJ(c84D8X@eH@s`v<$7(iTL#^Y zgiNHx!F>ba5@93s6f>LprA!nlpVQ`DEWS*gysiRRUP<9meoB5wzFD4L!7#~=94x@- zHob1qF%glUC^JUh>f?O7JIYpJBHwQl#TE@F|19v`*Jgiq|J@Dm)4R)!sDA2bd@_6f z_j@;or(#R=U&f!ttQ`^c9d?kY&7)H^YHL+yDdNavE|Fyz?i^j z!z9k=$h6M{&s4-DteMBOm&l*!#kj$Uu2rWUr6v4%u_RAhPA66CR_EyRr?UOhCXLHF zBF%HH&sqZ7GTP)Nb`@k5@6{h`gEgsjP2Ozi$LncmPrY^eY}UAK&!SRpRW4yGX$v|U zoL`%#uQfc7b%}H7b9wKw=Ys39b8tM}TK?kl;gaZb^m5`->XPL$|8i`fhv+r2DKRrq z0MQlCG&c&TB9FI45BEpTeJ)RKIxaG6!3EyAo2GX=uw#fb*irOUDkOsM_In1x%;~w) zUZ602eOFmm`Iybgzvsk$WZFBJ74N1}!AU(LJ~BUIH-b1)IFdOM zKT?_IrhJ;AF0kdyc&B+<`d#CPax3rU0cXEu;goA}w+eoiov_d4#ncorOBstJi#E$} z(qa-eOR|1ejkk4SjeNac4ScOx{r7sbT4AflNogySn$%jjnj`zq*2FgHw)cz5Hpx~z zwkr!+GX@L7v%*uq8Utr3XF&6q*?CM?iA)4N$9A=LJIAxf-Am?8^v%g*{!Y+4HDit03j8{*#}AEOJKsl5M#Hms1W(+AH@rt~ z{m;Mdv|q${6?idwr3iTlDGBL#WnJ1_I$khd^Iu6{lkFevX70W{hVcpT;rGe%dFg}e z)9QnMCu~6RCZ@&6mGYJXW`I6z}%7n<=lNo>vgJ_)iCz&jH z3DGWj3gHdAEMWp^4G{_{Gl`&(yRCzz!w%JoRC)L@empSA@UZn}b-kE!9m8b6IFv6z zWLl7u|H63pnl?)zEqRfZ_AO)cw3FrjWbshXP{a^kvIHys8(|lZ!?Ve)Oi&x>2o$}R zu=Z^Yxf?yC{Y~zh*k)rV+I9Jf#5yKyoutYxojo1YiaUdm7Cqm~$(h^F>C`0DjMSsl zr_?esqmhf`x3A<0z!7>8!4Y^-brDg~ZA368;wE<{!X|`}ci!Z_?f$xocW*RWw;fs5 z=1;AKevrMTYLL&bo+xy||U1l6CoiKoTh zbg`uQ-Co~AWI195;$@f+_8>McHa?vhU7J$1GNUrTa-T9;rXY`p@7a{nq|#hEHxIQv zS<{@y`PE3ReuKVxJ+ocVGQY#;qwhWC_4O0=y>{u#XllphroT+%<8boYeq;t|n|*iXwz?Xyxjvje zyrbTy?v;s(UMEi!+V|qT-|aWK>bHtsA}bcIcrSQyv$t_X-=gB2bt5?F>9{_)8(+xx zieAuM5T8@$)en9izIyiPbn{{TF_}^Ftdp$lw5NxJtxG!u^7rxq`v_GCjT`6B?E;L`bU7l35>FfFH^k@(3 zbm_=zH|Z4Vw3Sy^T9tWLn3ZL{Ce?pyAWatXGHa*x*sJ}z@kD=F zrOohO^nv23b5CMDip;(*dHQ)5dzpXR zA4&ch^6f|v>P}=r_>>sxljW9Pj(C_U$L_dsiyjr{42C zkljCSqaQ~flJ|=Y`dU4`c|5mz(b_#*wIDZJI^Wpx^#=bJ)9sIK`@@xw?GnEDuALP( z6*G1hc5}z8$LC8+zE6n&K#XtFloO!A4BE(x+;5&AKqC&7bNBG#?+nVnqa*nLhK_*j z?ChQYKo*^V&)~>2IPwgRJcA?8;K(yL@(hkVgCo!2$TK+d430d5BhTQ-GdS`Ljy!`S z&)~>2IPwgRJcA?8;K(yL@(hkVgCo!2$TK+d430d5BhTQ-GdS`Ljy!`S&)~@ahu}z= zIEl`g80%!R15G^JU1sYHa41Sus| zBs6tZr6~TV5DUco3uFp%22rSLi7U!UP|&jgfeMmRK%k_iB*h;tU=(buY(SutGCc*o zg|o8*KM?5V=EiCQvazu=cLcH8JDUH_1^$uC0?B1HbvC7kH1@w~1JX-7Cn2i;YZ)qG zBnm+@M-b$3ft({ zAu7nhzY?7x=4O9n{43eS#nBPs)}#r!`e)JqN&UB)V0Q<5M`so%urtKi$=nIj427T* z_?-*nBLz!C>~>T^&K7^_|7__m`Cqx>ASbXgtSoh?B&(!Xz7*~Qiv?D(gO zh3!Av5Cr~59|eK``GE^VynLXb$zcAw``e#`l;)2y{HGV(zf}L-`t7&s_c*8V=Y#zI zHzT-z3jgVs^_Nfx=0DxD{;B?_KhtmZ?~TSE8SZaxP5%`B(C?a^N)UP0D{|80rCnIQeM-oGPkzuk}i+-Uqg{%bu5()NEU^P7bGbEEOEVfd?C z|KQ^OS>&Iq;$KCMC?!GEk&stRzwS5yEJ%%AT-SuyzP+OA$O51e0r1+Xw);s@%`E{%7q_+<^iPW&A}7HK>uexNS@-vMNi#`8VmmvaEv7_I=) zNaI+EAE;BCM;gbvb^PP-!0uVoNE#5MI`3wLyLWz6FFZ2Fbo+Ez1nzxK!)&Ok8y8y%wT*~VE0i= _chunks; + // + private Map _world; + // private Texture2D _defaultTile; + // private const int TileSize = 32; public Game1() { @@ -21,7 +25,9 @@ public class Game1 : Game protected override void Initialize() { // TODO: Add your initialization logic here - _chunks = new Dictionary(); + _world = new Map(mapId: 0); + _world.LoadMap(); + // base.Initialize(); } @@ -29,8 +35,11 @@ public class Game1 : Game protected override void LoadContent() { _spriteBatch = new SpriteBatch(GraphicsDevice); + // _world.setContent(Content); // TODO: use this.Content to load your game content here + // _world._defaultTile = Texture2D.FromFile(GraphicsDevice, "src/Content/Tilemap.png"); + _world._defaultTile = Content.Load("Tilemap.png"); } protected override void Update(GameTime gameTime) @@ -48,7 +57,12 @@ public class Game1 : Game GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here + _spriteBatch.Begin(); + _world.Draw(ref _spriteBatch); + + _spriteBatch.End(); + // base.Draw(gameTime); } } diff --git a/src/Icon.bmp b/Icon.bmp similarity index 100% rename from src/Icon.bmp rename to Icon.bmp diff --git a/src/Icon.ico b/Icon.ico similarity index 100% rename from src/Icon.ico rename to Icon.ico diff --git a/src/Program.cs b/Program.cs similarity index 100% rename from src/Program.cs rename to Program.cs diff --git a/World/World.cs b/World/World.cs new file mode 100644 index 0000000..4beb3fe --- /dev/null +++ b/World/World.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; + +namespace tunnet.World; +struct World +{ + private class Tile // TODO: sprite, buildings[] + { + public int Id { get; } + public Tile(int id) => Id = id; + public static Tile FromId(int id) + { + return new Tile(id); + } + } + private class Chunk + { + public const int Width = 16; + public const int Height = 16; + internal Tile[,] Tiles { get; private set; } + + public Chunk() + { + Tiles = new Tile[Width, Height]; + } + } + private static class ChunkStorage + { + ///

+ /// Saves the given chunk to disk in a compact binary format: + /// Width×Height consecutive Int32 tile IDs. + /// + public static void Save(string filePath, Chunk chunk) + { + if (chunk == null) + throw new System.ArgumentNullException(nameof(chunk)); + + Directory.CreateDirectory(Path.GetDirectoryName(filePath) ?? "."); + using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write); + using var writer = new BinaryWriter(fs); + + for (int x = 0; x < Chunk.Width; x++) + { + for (int y = 0; y < Chunk.Height; y++) + { + // write each tile’s ID + writer.Write(chunk.Tiles[x, y]?.Id ?? 0); + } + } + } + public static void Save(int chunkX, int chunkY, Chunk chunk) + { + Save($"{chunkX}_{chunkY}.chunk", chunk); + } + + /// + /// Loads a chunk from the binary file format produced by Save(). + /// + public static Chunk Load(string filePath) + { + if (!File.Exists(filePath)) + throw new FileNotFoundException("Chunk file not found", filePath); + //TODO generate chunk instead + + var chunk = new Chunk(); + using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); + using var reader = new BinaryReader(fs); + + for (int x = 0; x < Chunk.Width; x++) + for (int y = 0; y < Chunk.Height; y++) + { + int id = reader.ReadInt32(); + chunk.Tiles[x, y] = Tile.FromId(id); + } + + return chunk; + } + public static Chunk Load(Point location) + { + var filePath = $"{location.X}_{location.Y}.chunk"; + if (File.Exists(filePath)) + return Load(filePath); + return null; + } + } + public class Map : Game + { + private readonly Dictionary _loadedChunks = new Dictionary(); + private IReadOnlyDictionary Chunks => _loadedChunks; + private readonly int id; + private readonly int TileSize; + public Texture2D _defaultTile; + + public Map(int mapId) + { + id = mapId; + TileSize = 32; + // Console.WriteLine(Content.Load("Tilemap.png").Width); + // _defaultTile = Texture2D.FromFile(GraphicsDevice, "Tilemap.png"); + // _defaultTile = Content.Load("Tilemap.png"); + } + + // Load the map by ID + public void LoadMap() + { + //TODO: Load map by ID + } + + // Generate a new map + private void GenerateMap() + { + //TODO: Implement map generation + } + + // Get a chunk (load if not in memory) + private Chunk GetChunk(Point location) + { + // var key = new Point(chunkX, chunkY); + if (!_loadedChunks.TryGetValue(location, out Chunk chunk)) + { + chunk = ChunkStorage.Load(location);// LoadChunkFromDisk(chunkX, chunkY); // Or generate + _loadedChunks[location] = chunk; + } + return chunk; + } + + // Access a specific tile + private Tile GetTile(int worldX, int worldY) + { + int chunkX = worldX / Chunk.Width; + int chunkY = worldY / Chunk.Height; + int tileX = worldX % Chunk.Width; + int tileY = worldY % Chunk.Height; + + // Handle negative coordinates + if (tileX < 0) tileX += Chunk.Width; + if (tileY < 0) tileY += Chunk.Height; + + return GetChunk(new Point(chunkX, chunkY)).Tiles[tileX, tileY]; + } + + // Unload distant chunks (memory management) + public void UnloadChunks(Point currentChunk, int keepRadius) + { + var keysToRemove = new List(); + foreach (var key in _loadedChunks.Keys) + { + if (System.Math.Abs(key.X - currentChunk.X) > keepRadius || + System.Math.Abs(key.Y - currentChunk.Y) > keepRadius) + { + ChunkStorage.Save(key.X, key.Y, _loadedChunks[key]); // Persist if needed + keysToRemove.Add(key); + } + } + keysToRemove.ForEach(k => _loadedChunks.Remove(k)); + } + + public void Draw(ref SpriteBatch spriteBatch) + { + foreach (var kvp in _loadedChunks) + { + Point chunkCoord = kvp.Key; + // var chunk = kvp.Value; + + for (int cx = 0; cx < Chunk.Width; cx++) + { + for (int cy = 0; cy < Chunk.Height; cy++) + { + // world‐space position in pixels + Vector2 pos = new Vector2( + (chunkCoord.X * Chunk.Width + cx) * TileSize, + (chunkCoord.Y * Chunk.Height + cy) * TileSize + ); + + // draw the default tile for now + spriteBatch.Draw(_defaultTile, pos, Color.White); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/app.manifest b/app.manifest similarity index 100% rename from src/app.manifest rename to app.manifest diff --git a/run.sh b/run.sh index ef64ddd..47c536a 100755 --- a/run.sh +++ b/run.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash echo "Running..." -exec dotnet run --no-build --project src/ +exec dotnet run --no-build diff --git a/src/src/World.cs b/src/src/World.cs deleted file mode 100644 index 65ea2ed..0000000 --- a/src/src/World.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using Microsoft.Xna.Framework; -// -namespace World; - -public class Tile -{ - public int Id { get; } - public Tile(int id) => Id = id; - public static Tile FromId(int id) => new Tile(id); -} -public class Chunk -{ - public const int Width = 16; - public const int Height = 16; - public Tile[,] Tiles { get; private set; } - - public Chunk() - { - Tiles = new Tile[Width, Height]; - } -} - -public static class ChunkStorage -{ - /// - /// Saves the given chunk to disk in a compact binary format: - /// Width×Height consecutive Int32 tile IDs. - /// - public static void Save(string filePath, Chunk chunk) - { - if (chunk == null) - throw new System.ArgumentNullException(nameof(chunk)); - - Directory.CreateDirectory(Path.GetDirectoryName(filePath) ?? "."); - using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write); - using var writer = new BinaryWriter(fs); - - for (int x = 0; x < Chunk.Width; x++) - { - for (int y = 0; y < Chunk.Height; y++) - { - // write each tile’s ID - writer.Write(chunk.Tiles[x, y]?.Id ?? 0); - } - } - } - public static void Save(int chunkX, int chunkY, Chunk chunk) - { - Save($"{chunkX}_{chunkY}.chunk", chunk); - } - - /// - /// Loads a chunk from the binary file format produced by Save(). - /// - public static Chunk Load(string filePath) - { - if (!File.Exists(filePath)) - throw new FileNotFoundException("Chunk file not found", filePath); - - var chunk = new Chunk(); - using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read); - using var reader = new BinaryReader(fs); - - for (int x = 0; x < Chunk.Width; x++) - for (int y = 0; y < Chunk.Height; y++) - { - int id = reader.ReadInt32(); - chunk.Tiles[x, y] = Tile.FromId(id); - } - - return chunk; - } - public static Chunk Load(int chunkX, int chunkY) - { - var filePath = $"{chunkX}_{chunkY}.chunk"; - if (File.Exists(filePath)) - return Load(filePath); - return null; - } -} -public class WorldMap -{ - private readonly Dictionary _loadedChunks = new Dictionary(); - - // Get a chunk (load if not in memory) - public Chunk GetChunk(int chunkX, int chunkY) - { - var key = new Point(chunkX, chunkY); - if (!_loadedChunks.TryGetValue(key, out Chunk chunk)) - { - chunk = ChunkStorage.Load(chunkX, chunkY);// LoadChunkFromDisk(chunkX, chunkY); // Or generate - _loadedChunks[key] = chunk; - } - return chunk; - } - - // Access a specific tile - public Tile GetTile(int worldX, int worldY) - { - int chunkX = worldX / Chunk.Width; - int chunkY = worldY / Chunk.Height; - int tileX = worldX % Chunk.Width; - int tileY = worldY % Chunk.Height; - - // Handle negative coordinates - if (tileX < 0) tileX += Chunk.Width; - if (tileY < 0) tileY += Chunk.Height; - - return GetChunk(chunkX, chunkY).Tiles[tileX, tileY]; - } - - // Unload distant chunks (memory management) - public void UnloadChunks(Point currentChunk, int keepRadius) - { - var keysToRemove = new List(); - foreach (var key in _loadedChunks.Keys) - { - if (System.Math.Abs(key.X - currentChunk.X) > keepRadius || - System.Math.Abs(key.Y - currentChunk.Y) > keepRadius) - { - ChunkStorage.Save(key.X, key.Y, _loadedChunks[key]); // Persist if needed - keysToRemove.Add(key); - } - } - keysToRemove.ForEach(k => _loadedChunks.Remove(k)); - } -} \ No newline at end of file diff --git a/src/tunnet.csproj b/tunnet.csproj similarity index 100% rename from src/tunnet.csproj rename to tunnet.csproj diff --git a/tunnet.sln b/tunnet.sln index aa36c25..e3c59bc 100644 --- a/tunnet.sln +++ b/tunnet.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tunnet", "src/tunnet.csproj", "{728D0B55-232F-4C2B-A31F-04EA4BFF4209}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tunnet", "tunnet.csproj", "{728D0B55-232F-4C2B-A31F-04EA4BFF4209}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution