00:13 < bridge> nice job 00:50 < bridge> ty 07:18 < bridge> Nice @kollpotato 07:22 < bridge> going to a farmer job finally? 07:48 < bridge> Yea I sent him into the melon garden 07:49 < bridge> gumo btw 08:07 < ws-client> https://zillyhuhn.com/cs/.1751868437.png 08:07 < ws-client> gm 08:17 < bridge> gm ^.^ 08:22 < bridge> the heck. 08:33 < bridge> how can a moderator know IDs of players? 08:35 < bridge> cl_nameplates_id 1 08:35 < bridge> you can type status in rcon as well 08:36 < bridge> There's also a scoreboard option 08:36 < ws-client> @Jupstar ✪ why is the time_get cached per tick? performance? or to be able to compare the values? Seems a bit complex to me 08:37 < ws-client> i am sure someone tryint to benchmark his tick functions got proper trolled by that 08:56 < bridge> Idk, wasn't my idea 09:02 < ws-client> oh i thought 09:02 < ws-client> hm 09:02 < ws-client> https://github.com/ddnet/ddnet/commit/aede6df2ca3b86b5b8c197731f0ca9d3c63031f5 09:03 < ws-client> @0xdeen why u do dis? 09:09 < bridge> Brother that was 11 years ago :KEKW: 09:10 < ws-client> older than the average Multeasymap enjoyer 09:11 < bridge> maybe to have the exact same time within a tick 👀 09:11 < ws-client> @jxsl13 for what xd 09:11 < bridge> my uneducated 2 cente, you are welcome. 09:11 < ws-client> it just breaks benchmarking and if you want to know if its the same tick look at the tick counter 09:11 < bridge> for calculations and stuff based on time? 09:12 < ws-client> ah so you use the timer for stuff that should be tick dependent 09:12 < ws-client> instead of using the tick 09:12 < ws-client> i see yea that might be it 09:13 < bridge> wtf i discovered a bug while implementing `broadcastid` 09:15 < bridge> why do some commands specify `v[id]` in usage and some use `i[id]`? 09:16 < bridge> there is the `pResult->GetVictim()` method 09:16 < bridge> but why does it exist anyways 09:16 < bridge> what's the point 09:17 < bridge> if it can be just `pResult->GetInteger(0)` 09:17 < ws-client> v[id] is more correct 09:18 < ws-client> not all commands have been ported yet 09:18 < bridge> what does v stand for again, value? 09:18 < ws-client> victim 09:18 < ws-client> i is integer 09:18 < bridge> actually? 09:18 < bridge> We tf 09:18 < ws-client> and v is supposed to be a client id 09:18 < ws-client> also accpets magic values such as ``all`` 09:18 < bridge> so does `pResult->GetVictim()` do anything special? 09:18 < ws-client> yes 09:18 < bridge> `all`? 09:18 < ws-client> ``all`` ``me`` and more idk 09:19 < bridge> it returns 0 for negative numbers 09:19 < ws-client> ``kill_pl all`` kills all 09:19 < bridge> which i would say is incorrect 09:20 < bridge> okay so i was right to use `pResult->GetVictim()` then 09:20 < bridge> but negative numbers should return an error for sure 09:31 < ws-client> i didnt look at the code but the idea might be that a victim can be used as array index for players without error checking because it can not be out of bounds 09:32 < ws-client> does it even call the callback when you provide a -1 victim? 09:38 < bridge> Callback? 09:38 < bridge> The command runs with client id 0 09:40 < bridge> ^ @kebscs 09:42 < bridge> So basically you can't know if `pResult->GetVictim()` returned 0 because the user typed in 0 or if it returned 0 because the user typed in a negative number 09:45 < bridge> So for example `muteid -42 10` mutes player with id 0 for 10 seconds 09:46 < bridge> And i think it shouldn't run the command 09:50 < bridge> Chiller you can also request the time directly uncached 10:07 < bridge> Old fastcap shouldn't send the flags 10:07 < bridge> If you're making your own fastcap then you can remove the flipping 10:28 < bridge> https://cdn.discordapp.com/attachments/1390347378372120576/1390681117241249984/image.png?ex=68692437&is=6867d2b7&hm=cba41823b5bd7838db72b221b8b77d2a77f3d41cd0fac725b7b0ff74ce3740cb& 10:28 < bridge> https://cdn.discordapp.com/attachments/1390347378372120576/1390681352436846673/image.png?ex=68692470&is=6867d2f0&hm=4fc1b62c4e2811856fcf1f594b658be9006fc5986bc928b71170f6d7e7bd5741& 10:28 < bridge> https://cdn.discordapp.com/attachments/1390347378372120576/1390681600852885595/image.png?ex=686924ab&is=6867d32b&hm=6d04295e0419f930cd8891fcd0b45eb7df54102f85f12b5047582a6b0ab62500& 10:28 < bridge> https://cdn.discordapp.com/attachments/1391481421717180557/1391484812228825090/image.png?ex=686c10b7&is=686abf37&hm=af8ac7d4180cf1bbffa66bae387e3c4e9c794f0b05b99adc296a642919c31d77& 10:29 < bridge> @Discord Mod 10:34 < bridge> how? 10:36 < bridge> oh that's nice 👍 10:38 < bridge> I assumned the server has no control over weapon flipping 10:39 < bridge> but ofc it has, since it loads the entities on map load 11:25 < bridge> chillerdragon: how the hell do snapshot uuids work 11:26 < bridge> ive read 2 different implementations 11:26 < bridge> ur protocol wiki 11:26 < bridge> even asked ai 11:26 < bridge> i have no idea what i am doing 11:48 < bridge> wait i think im cooking now 11:52 < bridge> can deleted item keys have uuids 11:53 < bridge> probably not 11:54 < bridge> ~~you are baked potato now?~~ 11:54 < bridge> yeah, using `all` as a victim works exactly as it should lol 11:54 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391718926714540102/image.png?ex=686ceac1&is=686b9941&hm=5857f786333c10ea6b2b006794088fc211b705c7da4d368bb6aa7bd187de7c05& 11:54 < bridge> no im just cooked 11:54 < bridge> cooked potat 11:58 < bridge> hot potato 12:12 < bridge> i think this is all wrong 12:12 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391723628101632080/image.png?ex=686cef21&is=686b9da1&hm=8cbdaf9ab048d497f841cd809f1165b1fd1fd65149d3ed332aa3cc0b832be944& 12:12 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391723628629983334/image.png?ex=686cef22&is=686b9da2&hm=d5f9c50cea7710a3401ced71f5bce8ecfacd629cbaefb22f1ab725ffb911d51d& 12:13 < bridge> how is y negative lmao 12:15 < bridge> you can jump out of the map, y negative, means up above the map 12:15 < bridge> I think it was about 200 blocks in each direction 12:15 < bridge> maybe 300, one was the render limit 12:19 < bridge> yep y can be negative 12:19 < bridge> but not in my case 12:19 < bridge> well im not deleting items from the snapshot maybe thats the issue 12:22 < bridge> I'm not sure how far you've read the docs, are you aware of the snap deltas? 12:23 < bridge> yes i am 12:23 < bridge> im applying the delta value to the original snapshot 12:24 < bridge> but do you do it on a new copy of the original snapshot? 12:24 < bridge> in demos the deltas build a chain, over the network they are independant of each other iirc 12:26 < bridge> wait i dont think i do 12:26 < bridge> i store the first snapshot as X, get the delta snapshot and apply it to X 12:26 < bridge> so that X is the current snapshot data 12:27 < bridge> i thought thats how snapshots work 12:27 < bridge> over the network, deltas might get lost. that is why later deltas can't rely on earlier deltas 12:28 < bridge> yeah i was wondering about that 12:28 < bridge> bcus i know ddnet can recover from snapshot packet loss 12:28 < bridge> wasnt sure how xd 12:28 < bridge> so each delta is a delta to the original snapshot, not a continuation of the last delta 12:29 < bridge> thanks i am going to try that now 12:29 < bridge> gl :) 12:29 < bridge> ty 13:14 < bridge> well one issue is gone 13:14 < bridge> another one came 13:15 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391739280690385018/image.png?ex=686cfdb5&is=686bac35&hm=56d1358ec497d1d98195c6fb155961e291722a1b07aa7f343f1341ddd4b6dc3f& 13:15 < bridge> snapshot item size is in billions 13:15 < bridge> https://tenor.com/view/yes-yes-sir-yayy-kataman-gif-12260883688244422951 13:30 < bridge> No way 1 year old pr merged 13:34 < bridge> 💪 13:57 < bridge> 8+- 14:11 < bridge> now we don't need a mouse anymore, we can just type a map 14:12 < bridge> Hey cursor, map me a blockmap 14:12 < bridge> checked out the feature and its pretty jank 14:13 < bridge> I wonder, why he didn't use ASCII offsets 14:13 < bridge> like we have 255 fields, and some control character could just be used for the arrows then 14:14 < bridge> its just a-z 0-9 and only works with tiles that are set up like the teeworlds default font 14:14 < bridge> so aip gores font doesnt work 14:14 < bridge> yeah exactly 14:14 < bridge> also ctrl+t is weird keybind 14:15 < bridge> making a font to letter generator would be very easy, if we'd just use ascii offsets 14:15 < bridge> and it starts placing text at same place your mouse was so you kinda have to aim beforehand 14:15 < bridge> making a font to letter/tileset generator would be very easy, if we'd just use ascii offsets 14:15 < bridge> and after you press enter you cant go back 14:16 < bridge> that's actual jank 😦 and I hoped you could press cntrl enter for next line 14:16 < bridge> i mean enter goes to new line 14:16 < bridge> but no way to go back to the previous one 14:19 < bridge> nvm arrows work ig 14:32 < bridge> @patiga yippe the data is correct now 14:32 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391758753086312458/image.png?ex=686d0fd8&is=686bbe58&hm=f77d0a7157cbbe9f9ecc73d8296b56348a4237561fa4753589b50d6e77e27ebb& 14:32 < bridge> but only once 14:32 < bridge> then it just stops updating xd 14:33 < bridge> Pog 🎉 15:52 < bridge> Sadly Heinrich insisted on fixed layout not supporting custom font offsets. I had two proposals for that implemented over the years 15:53 < bridge> @essigautomat: wdym by ascii offsets 15:54 < bridge> I proposed a pr once where error messages could be silenced for all and kept for single. Was rejected. Its output is not nice but yes it works as it should 15:56 < bridge> You mean the ddnet extensions? They get registered. In the beginning of the snap you have a few items with the uuid as payload the define the type id that will be used for that uuid during this session. All new snap items with that type id are of type matching that uuid 15:59 < bridge> Wdym by original snapshot? The network uses deltas to previous snapshots. The data loss problem is solved by specifying the base snapshot by gametick. The client either has that exact snapshot or a full snapshot is resend as baseline on fatal error. 16:00 < bridge> You can navigate before typing. Where else’s should it start? 16:01 < bridge> i thought you would kinda place it like a tile 16:01 < bridge> or idk 16:01 < bridge> You can do so 16:01 < bridge> how 16:01 < bridge> Move your mouse like you would with a tile and then go into text mode 16:01 < bridge> it insta places it after i press ctrl t 16:02 < bridge> Move first 16:02 < bridge> Where is the difference 16:02 < bridge> yea its not intuitive i mean 16:02 < bridge> i might not notice the text indicator 16:02 < bridge> I see 16:02 < bridge> To me it was 16:02 < bridge> But yea have the mouse become a floating cursor could also work 16:03 < bridge> No hard feeling on it. Did not try the ux could be as good 16:03 < bridge> But your feedback is a bit late you had like 4 years to test it xd 16:03 < bridge> the pr got lost 16:03 < bridge> too old 16:03 < bridge> Now saying because of that it’s pretty jank is rude .\_. 16:04 < bridge> dw its a good addition 16:04 < bridge> not sure who writes a lot of text in maps 16:04 < bridge> but ig itll be easier now 16:04 < bridge> Only rare adventure maps 16:04 < bridge> But even I typing out single words will be using it 16:04 < bridge> I usually type at least one word per map xd 16:05 < bridge> But I won’t be able to use it because of fixed offsets bruv 16:05 < bridge> Makes me so mad that the feature is basically useless for so many font mapres 16:05 < bridge> While it would be so easy to be flexible 16:17 < bridge> https://www.commfront.com/pages/ascii-chart 16:17 < bridge> 16:17 < bridge> what developer doesn't know ascii tables? 16:26 < bridge> omg thats why some type ids are so huge 16:27 < bridge> thank you the protocol genie 16:27 < bridge> i love u 16:27 < bridge> lmao now i have to fix it again 16:27 < bridge> epic 16:27 < bridge> thats why it was stuck 16:33 < bridge> @essigautomat: I know ascii but I don’t know what you propose exactly 16:36 < bridge> I am not sure about the full snapshot on error tho. Would have to look that up again. You don’t need to worry much about it in the beginning. @kollpotato you build a client right? Just store a few snapshots and their game tick. And when you get a new one delta it against the one from storage based on the delta tick 16:37 < bridge> https://chillerdragon.github.io/teeworlds-protocol/07/system_messages.html#NETMSG_SNAP_delta_tick 16:37 < bridge> sounds epic, gonna do that now 16:37 < bridge> because i only store one snapshot now 16:37 < bridge> wasnt sure was delta tick even did xd 16:38 < bridge> is there any library that i can get player info etc from a server, like teeworlds-info npm lib but it only gets server name-maxplayers-ping info 16:38 < bridge> Now you know! Now you pro @kollpotato 16:38 < bridge> @vahemaaa: curl 16:38 < bridge> :D just use the http json master 16:38 < bridge> u proer 16:38 < bridge> me still nub 16:39 < bridge> no u 16:39 < bridge> thank you so much kral! 16:45 < bridge> I propose to use the tileset offset as ascii offsets 16:48 < bridge> @essigautomat: why? 16:48 < bridge> You mean like place A at 0x41 in the mapres? 16:48 < bridge> so we can support special character if we want to AND generate tilesets from fonts directly in an easy manner 16:48 < bridge> I don’t think there is a single mapres that has these offset 16:49 < bridge> like what custom layout does this have now? Do we only support A-Z in upper case and 0-9? 16:49 < bridge> So it wouldn’t even be compatible with any font that’s out there right now 16:49 < bridge> Yes 16:58 < bridge> Just update the mapres that aren't in the standard format. Overtime it'll fix itself 17:01 < bridge> There are more mapres in or close to the alignment including official ddnet ones that I used . There are 0 in ascii. And I’m not sure designers even know about the feature or its offsets 17:02 < bridge> Mine already works. Ascii does not 17:02 < bridge> And for what? That it’s easier to create fonts? It’s not hard to align them in the way they are 17:02 < bridge> If you want to automate it it’s not hard either 17:03 < bridge> Punctuation would be cool but then even less coverage can be guaranteed by existing mapres and not everyone is used to QWERTZ anyways 17:07 < bridge> no, most are used to QWERTY :owo: 17:09 < bridge> Definitely don't use ascii, the standard format should be something that is actually already used by some things at least 17:16 < bridge> chillerdragon: rust borrow checker slows me down a lot xd 17:17 < bridge> i should have used scratch 17:19 < bridge> i either have to redesign the entire client or have about 4 nested match statements resulting in 8 tabs 17:26 < ws-client> thanks @learath2 tell that to assa xd 17:27 < ws-client> @kollpotato rust moment 17:27 < bridge> indeed rust moment 17:27 < bridge> blazingly fast borrowing error 17:42 < bridge> @robyt3 could you test if the notification pr builds for you 17:43 < bridge> i replaced winrt with abi,wrl so maybe it doesnt even need the turned off exceptions 18:04 < ws-client> https://zillyhuhn.com/cs/.1751904186.png i have no custom skin and all skin downloads off and am on a 0.6 server xd 18:06 < bridge> lmao 18:34 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391819710504632370/GvRLqdaXAAcQo5G.png?ex=686d489d&is=686bf71d&hm=dfc689c87f1c2cbe9766a65f20efdb027346323e868702cc46ac6920e559a3a2& 18:35 < bridge> I most certainly did not know this was possible, wtf 18:36 < bridge> my rust cant do that 18:37 < bridge> I guess it is clever 😄 18:37 < bridge> Why would you want to do that tho 18:38 < bridge> To demonstrate that you can 18:39 < bridge> I think you can edit the AST tree in rust 18:39 < bridge> So idk 18:40 < bridge> Seems like that could make this possible 18:40 < bridge> Probably, rust macros are stupid powerful 18:41 < bridge> https://github.com/rust-lang/rfcs/issues/1579#issuecomment-1398724803 yep 18:42 < bridge> Doesn't even need macros 😄 18:45 < bridge> Btw why aren't type systems more powerful? 18:45 < bridge> its hard 18:45 < bridge> What if i want an integer in the range -1 to 2137? 18:45 < bridge> rust has got one of the best ones 18:45 < bridge> That would be an awesome type 18:45 < bridge> make a wrapper type for i16 18:45 < bridge> and validate with the constructor function 18:45 < bridge> Or i feel like sometimes i want struct members to be optional only in certain situations 18:46 < bridge> enums! 18:46 < bridge> Okay but like the type system could also help ig 18:47 < bridge> A struct { 18:47 < bridge> A: T 18:47 < bridge> B: T 18:47 < bridge> } 18:47 < bridge> Can be casted safely into 18:47 < bridge> struct { 18:47 < bridge> A: ?T 18:47 < bridge> B: ?T 18:47 < bridge> } 18:49 < bridge> in rust you would make a method for this 18:50 < bridge> but in c/c++ i suppose you can just cast it 18:50 < bridge> I mean in C optionals don't exist 18:50 < bridge> Only null pointers 18:51 < bridge> yes i love dereferencing null pointers in c 18:51 < bridge> null pointers save a whole one byte comparing to rust 18:51 < bridge> clearly a win 18:52 < bridge> Does it? 18:52 < bridge> How do optionals work 18:52 < bridge> I assume an additional bool can work 18:53 < bridge> But if you have an optional u8 18:53 < bridge> But you know it's never 0 18:53 < bridge> Then 0 can mean no value 18:53 < bridge> yes rust has niche optimization 18:53 < bridge> im not a pro in all that stuff but i know it exists 18:53 < bridge> So `non-zero u8` is actually a useful type to have 18:54 < bridge> thats why rust is the best 18:54 < bridge> and every other languages sucks 18:54 < bridge> i sound like a cultist 18:55 < bridge> Rust sucks 18:55 < bridge> Rust gives you a lot of time to talk on discord while your code is compiling lol 18:55 < bridge> std::optional 18:55 < bridge> its c++ 18:56 < bridge> In cpp i have no idea how it works 18:56 < bridge> yeah gazillion dependencies have to be compiled from scratch 18:56 < bridge> But there probably is a way to cast optional T into T 18:56 < bridge> c/c++ just have shared objects 18:57 < bridge> sounds unsafe 18:57 < bridge> why compare 50 year old c to rust 18:57 < bridge> because i have free will 18:57 < bridge> C is awesome 18:57 < bridge> Even tho it sux 18:58 < bridge> I use zig a lot recently 18:58 < bridge> @learath2 did you see what he wrote 18:58 < bridge> C is awesome I agree 19:00 < bridge> https://tenor.com/view/cpp-dev-bad-developer-code-gif-12287264072566252661 19:01 < bridge> xD 19:01 < bridge> First of all, not trivial, operations between ints of different ranges would lead to very different possible output ranges. 19:01 < bridge> Second there are some languages where it is a thing, like Ada 19:02 < bridge> 1. It's really hard 19:02 < bridge> 2. Someone did it anyways 19:02 < bridge> wow its really a thing 19:02 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391826839168618657/image.png?ex=686d4f41&is=686bfdc1&hm=8c9bddbd51ff110d3334576d010985dff9a753c2bfe40b6a461af99e4d1fb214& 19:03 < bridge> that does not look productive 19:03 < bridge> and no one else really bothered with it afterwards, so it is hard and it doesn't get enough use to make it worth compiler peoples times 19:03 < bridge> There is wuffs by google that also has types that have ranges, (even more generally contracts tbf) 19:04 < bridge> There are the same problems in traditional languages too 19:05 < bridge> Because u8 * u8 could need u16 19:06 < bridge> In C pretty much everything works and it's not obvious what's going to happen 19:06 < bridge> Well we already know how to work with that. There is hardware support to handle it properly. What happens when a 0...10 overflows? The overflow bit isn't set so just to detect it you need branching everywhere 19:07 < bridge> Well we already know how to work with that. There is hardware support to handle it properly. What happens when a 0...10 overflows? The overflow flag or the carry flag isn't set so just to detect it you need branching everywhere 19:08 < bridge> I am not sure i understand what you mean 19:09 < bridge> There are flags on the CPU level 19:09 < bridge> But how can i detect overflows in code? 19:09 < bridge> doesnt overflow cause an interrupt? 19:09 < bridge> and then somehow it catches that interrupt and handles how it wants 19:09 < bridge> I don't think so 19:09 < bridge> Idk 19:10 < bridge> rust in debug mode can just print it, in release build it lets the value go to 0 19:10 < bridge> The compiler can insert overflow detection 19:11 < bridge> But idk how it works 19:11 < bridge> Does not compile 19:11 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391828887071101049/output.txt?ex=686d5129&is=686bffa9&hm=b774827654db112d71a4c92fda229e26ed32cf9a6279715bc986c9a873518778& 19:13 < bridge> To check that your u8 * u8 overflowed is trivial. To check that your 0...10 * -3...300 overflowed is not, it requires an extra subtraction. So there is a performance penalty. Furthermore the multiplication of those will result in a -3...3000, the division will result in a -infty...10, the addition -3...310. It gets annoying very quick 19:14 < bridge> Well okay i understand 19:14 < bridge> Overall, it's a feature not many people want with many small quirks 19:14 < bridge> It's just an interesting idea 19:14 < bridge> So it's hard to get a compiler person to care enough to implement it 19:14 < bridge> intrinsics 19:14 < bridge> You should check out wuffs 19:14 < bridge> rust has overflowing ops that returns a bool 19:14 < bridge> https://docs.rs/num-traits/latest/num_traits/ops/overflowing/trait.OverflowingAdd.html 19:15 < bridge> https://github.com/google/wuffs 19:15 < bridge> Zig requires explicit casting a lot of the time 19:16 < bridge> @pilonpl more than ints with ranges its more interesting to have ints with values you know wont be used 19:16 < bridge> this is heavily abused by rust 19:16 < bridge> for example we have NonZerou64 19:16 < bridge> Yeah i talked about it 19:16 < bridge> this allows niche optimizations on the zero value 19:16 < bridge> But maybe other compilers can do that too? 19:16 < bridge> https://doc.rust-lang.org/std/primitive.i8.html#method.overflowing_add 19:16 < bridge> https://doc.rust-lang.org/std/primitive.i8.html#method.overflowing_add 19:16 < bridge> Maybe LLVM itself can do that 19:16 < bridge> https://doc.rust-lang.org/std/num/type.NonZeroU64.html 19:17 < bridge> i dont think llvm does that, i dont know any operation that allows u to give such info on top of my head 19:17 < bridge> i worked a bit with llvm 19:17 < bridge> first of all, this opt is used in enums 19:17 < bridge> So how do optionals work usually? 19:17 < bridge> llvm has no enums 19:17 < bridge> u implement them urself 19:18 < bridge> optionals would be enums i guess which llvm also doesnt implement 19:18 < bridge> Any ideas how to fix? 19:18 < bridge> in llvm u would make them by "interpreting" the bits based on a field 19:18 < bridge> enums are really just structs 19:18 < bridge> (tagged unions) 19:18 < bridge> I thought maybe .Ref but I see ReleaseAndGetAddressOf also fails 19:18 < bridge> https://mapping-high-level-constructs-to-llvm-ir.readthedocs.io/en/latest/basic-constructs/unions.html 19:19 < bridge> isnt that just pipes? 19:19 < bridge> https://discourse.nixos.org/t/pre-rfc-pipe-operator/28387 19:19 < bridge> I have no idea how this stiff works 19:19 < bridge> ```llvmir 19:19 < bridge> ; basic type definition 19:19 < bridge> %Foo = type { i8, [8 x i8] } 19:19 < bridge> ; Variants of Foo 19:19 < bridge> %Foo_ABool = type { i8, i8 } ; tagged with 0 19:19 < bridge> %Foo_AInteger = type { i8, i32 } ; tagged with 1 19:19 < bridge> %Foo_ADouble = type { i8, double } ; tagged with 2 19:19 < bridge> 19:19 < bridge> ; allocate the first Foo 19:19 < bridge> %x = alloca %Foo 19:19 < bridge> ; pointer to the first element of type i8 (the tag) 19:19 < bridge> %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0 19:19 < bridge> ; set tag to '1' 19:19 < bridge> store i8 1, i8* %0 19:19 < bridge> ; bitcast Foo to the right Foo variant 19:19 < bridge> %1 = bitcast %Foo* %x to %Foo_AInteger* 19:19 < bridge> ; store the constant '42' 19:19 < bridge> %2 = getelementptr inbounds %Foo_AInteger, %Foo_AInteger* %1, i32 0, i32 1 19:19 < bridge> store i32 42, i32* %2 19:19 < bridge> 19:19 < bridge> ; allocate and initialize the second Foo 19:19 < bridge> %y = alloca %Foo 19:19 < bridge> %3 = getelementptr inbounds %Foo, %Foo* %y, i32 0, i32 0 19:19 < bridge> ; this time the tag is '2' 19:19 < bridge> store i8 2, i8* %3 19:20 < bridge> ; cast to variant and store double constant 19:20 < bridge> %4 = bitcast %Foo* %y to %Foo_ADouble* 19:20 < bridge> %5 = getelementptr inbounds %Foo_ADouble, %Foo_ADouble* %4, i32 0, i32 1 19:20 < bridge> store double 1.337000e+03, double* %5 19:20 < bridge> ``` 19:20 < bridge> ```llvm 19:20 < bridge> ; basic type definition 19:20 < bridge> %Foo = type { i8, [8 x i8] } 19:20 < bridge> ; Variants of Foo 19:20 < bridge> %Foo_ABool = type { i8, i8 } ; tagged with 0 19:20 < bridge> %Foo_AInteger = type { i8, i32 } ; tagged with 1 19:20 < bridge> text bomb 19:20 < bridge> I started implementing lox programming language from that book someone recommended in #off-topic 19:20 < bridge> https://learn.microsoft.com/en-us/archive/blogs/ericgu/minus-100-points this is a good link whenever someone is wondering why a language doesn't have X feature 19:20 < bridge> i have an adversion to clicking M links 19:21 < bridge> aversion 19:21 < bridge> * 19:21 < bridge> idk word 19:21 < bridge> https://mildbyte.xyz/blog/solving-wordle-with-uv-dependency-resolver/ 19:21 < bridge> Lots of great engineers at microsoft and more than a decade of devblogs there 19:21 < bridge> ye but the web is ugly af 19:21 < bridge> Yup 19:22 < bridge> And their services don't work well 19:23 < bridge> Things just feel slow 19:23 < bridge> And stuff often doesn't update even after weeks lol 19:24 < bridge> @tsfreddie actually you might find this one interesting too 😄 19:24 < bridge> So like when you update your profile picture it is stuck on the old one for weeks 19:25 < bridge> does llvm figure out the alignment on its own? 19:25 < bridge> %Foo cant be 9 bytes right 19:25 < bridge> no, thats why datalayout string exists 19:25 < bridge> https://llvm.org/docs/LangRef.html#langref-datalayout 19:26 < bridge> depends on data layout, but u can define the padding urself too 19:27 < bridge> https://doc.rust-lang.org/std/option/index.html#representation I wonder how they achieve this one 19:27 < bridge> hmm i dont remember but both is valid, because u can init the struct and use undefined or poison values on the padding 19:27 < bridge> mostly niche opt 19:28 < bridge> Option => use nullptr as None for option, same size as box which is a ptr 19:28 < bridge> i wonder why would you but thats cool 19:28 < bridge> Option<&U> => use nullptr for None, as ref cant be null 19:28 < bridge> num::NonZero* => use zero for None 19:28 < bridge> ptr::NonNull => use null for none 19:29 < bridge> But how is it implemented? Can one define their own `Option` somehow? or does it need the frontend to emit special sauce? 19:29 < bridge> and so on 19:29 < bridge> no, its only compiler privilege 19:29 < bridge> what if i want a type NonFiveU8 19:29 < bridge> @learath2 but the optimizer goes much deeper than this, on enums it can find places to put the tag that are not obvious 19:29 < bridge> should be possible with using NonZero as the base type maybe 19:29 < bridge> I see, so they specially mark these types and when you have an `Option` that is one of those types it generates different type and uses the 0 19:30 < bridge> some ppl asked NonMaxU64 and so on 19:30 < bridge> u can achieve https://docs.rs/nonmax/latest/nonmax/struct.NonMaxU64.html via a mask on the zero value 19:30 < bridge> this is a library 19:30 < bridge> Maybe you could have other properties too like NotPrimeU64 lol 19:30 < bridge> yeah woudl be coolto have 19:31 < bridge> not just for option, its for enums in general, more specifically for the tag marker 19:31 < bridge> I wonder what the limits are 19:31 < bridge> How much stuff can you do at compile time 19:31 < bridge> Hm, how did they even achieve this? is is somehow abusing NonZero? 19:31 < bridge> human will is the limit 19:31 < bridge> this is where unsafe enters, with NonZero, u cant make a NonZero that has the value zero via safe rust 19:31 < bridge> so they can use the zero for such purpose 19:32 < bridge> https://www.0xatticus.com/posts/understanding_rust_niche/ 19:32 < bridge> this explains a bit 19:33 < bridge> That's actually really smart 19:34 < bridge> rust is just magic 19:34 < bridge> Are there maybe other similar things 19:35 < bridge> I feel like i should learn assembly 19:35 < bridge> Because not knowing assembly is a bit annoying 19:36 < bridge> learn llvm ir xd 19:36 < bridge> its cross platform 19:36 < bridge> But all those registers with weird names are hard to figure out 19:37 < bridge> And those are not even physically separate registers 19:37 < bridge> Oh this is quite clever, it just stores a `NonZero`, but when storing and loading it XORs with the max 19:37 < bridge> I wonder if the compiler is smart enough to optimize that out though, or while trying to avoid a byte of extra storage you end up having to do an XOR all the time working with the value 😄 19:38 < bridge> What 19:38 < bridge> Why is XOR necessary 19:39 < bridge> It turns the real max into a zero 19:39 < bridge> Then it can be stored in a non-zero 19:39 < bridge> Then it can benefit from the size optimization for `Option` 19:40 < bridge> Sure but why would you want to store NonMax in a NonZero lol 19:40 < bridge> So it can benefit from the size optimization 19:40 < bridge> Can't you just use max as the null? 19:40 < bridge> rust only has nonzero so you have to hack around to get your own nonmax 19:41 < bridge> You can, and this trick is how, you turn the max into a zero. The compiler doesn't know what a `NonMax` is, it only has special sauce for `NonZero` 19:41 < bridge> That's a bit dumb 19:41 < bridge> No idea 19:45 < bridge> Okay so rust is so great so how can you handle stack overflows or failed heap allocations? 19:47 < bridge> Stack overflows in particular are not obvious 19:47 < bridge> Because recursion 19:47 < bridge> You panic 19:48 < bridge> Well that's great 19:49 < bridge> Otherwise you would probably just segfault anyways 19:49 < bridge> Failed heap allocations can be checked and recovered from by using your own allocator 19:49 < bridge> But it feels like there should be some way of handling stack overflows 19:50 < bridge> Stacks are so interesting btw 19:50 < bridge> Because even C which is so low level has an implicit stack 19:51 < bridge> you have methods like overflowing_add wrapping_add to not panic 19:51 < bridge> ive almost never used them but they exist 19:51 < bridge> that's not the kind of overflow we are talking about here 19:51 < bridge> oh 19:51 < bridge> I guess cpus have special instructions for stacks too 19:51 < bridge> oops i messed up the terms 19:52 < bridge> stack overflow means 19:52 < bridge> no memory 19:52 < bridge> means no more stack memory tbh 19:52 < bridge> yes 19:52 < bridge> `std:🧵:Builder::stack_size(10000 * 10000)` 19:52 < bridge> 19:52 < bridge> ez fix 19:52 < bridge> yes true 19:52 < bridge> just buy more ram 19:52 < bridge> i rather download that sxhii 19:52 < bridge> i rather download that tbh 19:53 < bridge> Btw can you like move whole pages of memory? 19:53 < bridge> Shouldn't that be basically free? 19:54 < bridge> Idk how useful that is 19:54 < bridge> But seems interesting 19:55 < bridge> The kernel can re map whole pages for basically free yes 19:57 < bridge> Actually since you have the whole address space available you could place the stack at the very end and have pretty much unlimited space for it to grow 19:57 < bridge> Where does the heap go then? 19:57 < bridge> At the start 19:58 < bridge> It's actually interesting 19:58 < bridge> You often need much more space on the heap than on the stack 19:59 < bridge> Yeah so stack at the end and it grows downwards 19:59 < bridge> heap at the top and it grows upwards? 😄 20:00 < bridge> The address will get to 0 at some point, the stack has to start somewhere 20:01 < bridge> Idk whatever 20:01 < bridge> I just realised that you have the whole address space all the time 20:02 < bridge> You just can't use it at once 20:02 < bridge> So why can't you allocate an array on page 1 and then when you need it just magically allocate page 2? 20:02 < bridge> Why copy stuff when you can just grow 20:04 < bridge> address randomization my friend 20:04 < bridge> and in general no guarantee that you can get a contiguous block of memory 20:04 < bridge> address randomization my friend 20:04 < bridge> and no guarantee that you can get a contiguous block of memory 20:04 < bridge> (btw where they are mapped doesn't matter all that much, if you allow them to grow forever, the kernel will just keep growing them by mapping in pages there) 20:04 < bridge> ((as long as the kernel has available memory, and you are not out of address space)) 20:04 < bridge> though yes when you really need it you *can* just grow 20:04 < bridge> but you need to ask really nicely 20:05 < bridge> So like can you actually do that on linux? 20:05 < bridge> i wonder what happens if the OS tries to map an entire page to a reserved one 20:05 < bridge> does it silently fail, does your house burn down? who knows... 20:05 < bridge> Because usually you just call malloc and you can't control where in your address space you will get the pointer to 20:06 < bridge> Probably because there is an abstraction layer between malloc and the os 20:06 < bridge> `ulimit -s unlimited` will give you a forever growing stack 20:06 < bridge> `malloc` will just get more pages from `mmap` 20:07 < bridge> So is this used in real life? Seems OP 20:07 < bridge> Not having to copy data 20:07 < bridge> (heap memory is not contiguous as some graphics might suggest, in the olden days of `sbrk` maybe) 20:08 < bridge> ofc, heaps and stacks grow without ever copying data by using virtual memory 20:08 < bridge> I mean heap for sure 20:09 < bridge> (even if you don't set `ulimit -s unlimited` modern kernels won't give you all the memory you requested, they will only map as needed, when you use it) 20:10 < bridge> Yeah i actually heard about that 20:10 < bridge> That you can just allocate whatever you want and it won't be used untill you use it i guess 20:10 < bridge> Idk exactly 20:11 < bridge> Seems weird 20:11 < bridge> Because how can memory be allocated at the moment that i want to use it? 20:12 < bridge> Feels like that would require some special hardware support 20:13 < bridge> That's how it happens indeed. The cpu will raise a page fault, the kernel catches it, maps a new page (or a couple new pages) to where the page fault happened 20:13 < bridge> Oh okay actually that makes sense 20:13 < bridge> If you had a stack size limit set, it'll check whether you are over your allowance, if you are then you get a segfault 20:14 < bridge> I think it even has a special error message for stack overflows 20:15 < bridge> You can look at `/proc//maps` for a process to see how everything is mapped. The only true limit is address space, if you need more stack and there just is something else in the way already allocated, there is nothing to be done 20:15 < bridge> (there are I think some implementations that support a discontiguous stack, but I can't really think of any, I just know there was support in gcc for it) 20:16 < bridge> Interesting stuff for sure 20:16 < bridge> Are there any languages that don't have a stack? 20:17 < bridge> cat /proc/self/maps usually the fastest to tell people to see 20:18 < bridge> I mean if u only want to get an overview of any process 20:18 < bridge> I mean if u only want to get an overview of any process (in this case cat) 20:19 < bridge> Hm, it's a curious question. Idk any, it's a great way to think about programs, with how calls work, but I'm pretty sure you can reduce it to some other structure too 20:19 < bridge> It's also interesting that you can analyse the stack growth quite well at compile time 20:19 < bridge> Recursion is a problem 20:19 < bridge> And dynamic libraries 20:20 < bridge> If you code in straight assembly you can technically avoid having a stack and just completely freehand the memory layout 20:21 < bridge> You could reserve space in your functions compiled machine code for the variables and use that 20:22 < bridge> I think I read about something like that in an old Z80 assembly manual 20:23 < bridge> (no-recursion allowed) 20:23 < bridge> You can have mini-stacks, one per each of your functions 😄 20:24 < bridge> One common mistake is returning a pointer to a stack allocated value 20:25 < bridge> Because it can be kinda weird that you can pass a pointer to a stack allocated value but you can't return one 20:25 < bridge> A bit asymmetric 20:27 < bridge> idk, in general it's just very hard for me to think in terms of what a language that does not operate on some sort of stack might look like, calling functions is very "stacky" in essence 20:27 < bridge> Yeah 20:28 < bridge> I wonder how first programmers came up with the stack 20:28 < bridge> Because i don't it's obvious you should do things in this specific way 20:29 < bridge> Because i don't think it's obvious you should do things in this specific way 20:30 < bridge> I wonder what alternative paths computers could've taken 20:30 < bridge> Because it seems like there were lot's of possibilities 20:30 < bridge> Well you needed somewhere to store stuff when you ran out of registers 20:31 < bridge> Storing them discontinuously is stupid, so that leaves a queue and a stack 20:31 < bridge> A stack needs a single pointer, a queue needs 2 20:34 < bridge> Idk how to smoothly change the topic but you can also have 4 by 4 grid of CPUs and FIFOs between them 20:34 < bridge> Which is such an interesting idea 20:36 < bridge> Apparently it's useful for low latency trading 20:36 < bridge> And an interesting zachatronics game 20:37 < bridge> You should play TIS-100. It's a very fun game 20:37 < bridge> Yeah 20:37 < bridge> I played half of it 20:37 < bridge> And it's great 20:37 < bridge> I solved the secret puzzle 20:38 < bridge> Having to read a manual to play a game makes me feel smart lol 20:39 < bridge> I still don't know the secret opcode tho 20:39 < bridge> @pilonpl https://doi.org/10.1007/BF01386232 here found you the paper which proposed the idea of a call stack by none other than dijkstra himself 20:40 < bridge> In the olden days space was wasted because we had fixed places for every functions scratch space. He proposed the stack which fixes both the recursion issue and the memory waste issue 20:40 < bridge> Wow 20:41 < bridge> Funny how people actually cared about memory back then. If they told any modern programmer about such a problem they'd say just buy more ram 20:41 < bridge> Btw the Dijkstra's algorithm seems so simple 20:41 < bridge> And people really thought it was an unsolvable problem lol 20:42 < bridge> It was simple to Dijkstra too, iirc he said he designed it over coffee while travelling 20:42 < bridge> And there is also A* 20:43 < bridge> Which makes the algorithm faster 20:43 < bridge> But i guess it's a bit different 20:43 < bridge> Because i think Dijkstra's algorithm finds the shortest path to all nodes 20:43 < bridge> And A* only to one specific node 20:43 < bridge> Or something like that 20:44 < bridge> A* is a solution to a different problem 20:44 < bridge> Dijkstra's algorithm finds the shortest distance to every node on an undirected graph 20:44 < bridge> A* finds the shortest path to a single target node 20:46 < bridge> Yeah 20:46 < bridge> A* is just dijkstra on a modified graph 20:48 < bridge> Is it? Never really thought of it as such 20:48 < bridge> I watched a lot of youtube videos about this 20:49 < bridge> And i remember this fact being mentioned in one 20:49 < bridge> Unless it's totally false 20:49 < bridge> That also a possibility because i have no idea how this stuff works lol 20:49 < bridge> The other way around you could see Dijkstra's algorithm as a special case of A* 20:50 < bridge> (where the heuristic function is constant and 0) 20:50 < bridge> Then A* has to expand every node like Dijkstra, giving you all the shortest distances 20:51 < bridge> Yeah i guess 20:53 < bridge> making connections between seemingly unrelated concepts is what math is all about 20:56 < bridge> How do you build so I can check 20:57 < bridge> MSYS2, GCC, Ninja 20:57 < bridge> Windows? 20:57 < bridge> yes, MSYS2 is Windows only 21:58 < bridge> the build instantly fails for me 21:58 < bridge> ``` [1/261] C:\msys64\mingw64\bin\g++.exe -DCONF_INFORM_UPDATE -DCONF_VIDEORECORDER -DGAME_RELEASE_VERSION_INTERNAL=19.4 -DGLEW_STATIC -DNOMINMAX -DNTDDI_VERSION=0x06000000 -DUNICODE -DWIN32_LEAN_AND_MEAN -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=0 -D_UNICODE -D_WIN32_WINNT=0x0600 -Dsteam_api_EXPORTS -IC:/Users/ok/source/repos/ddnet-master/ddnet/out/build/Mingw64-Release/src -IC:/Users/ok/source/repos/ddnet-master/ddnet/src -IC:/Users/ok/source/repo 21:58 < bridge> FAILED: CMakeFiles/steam_api.dir/src/steam/steam_api_stub.cpp.obj ``` 21:59 < bridge> Delete `libwinpthread-1.dll` from your build directory after configuring if you use ddnet-libs, this dll is too old for the latest MSYS2, would also need to be recompiled by deen at some point 22:00 < bridge> Or launch the build process and client from a different folder that does not contain the dll 22:02 < bridge> same thing after deleting it 22:04 < bridge> Try to copy the entire command that failed, add the parameter `-v` after `g++.exe` and execute it manually 22:04 < bridge> or `--verbose` 22:07 < bridge> https://cdn.discordapp.com/attachments/293493549758939136/1391873392327659690/image.png?ex=686d7a9c&is=686c291c&hm=2b344232b3c1b50e88311653f730b41c33467f2280d6c8bea12958af2ac91a9c& 22:08 < bridge> That should be fixed by deleting the dll 22:10 < bridge> ok seems to work, had to deleted from every cmake-build folder 22:10 < bridge> ok seems to work, had to delete from every cmake-build folder 22:10 < bridge> ty 22:13 < bridge> i wonder if deen would be ok replacing his release system with a GHA workflow, if it was proposed. this is getting a little out of hand. windows is still the most popular platform for players by far so just because the relevant devs aren’t experienced with it or don’t have time to mess with it doesn’t mean it’s not important to keep working & up to date 22:14 < bridge> `C:/Users/ok/source/repos/ddnet-master/ddnet/src/engine/client/backend/vulkan/backend_vulkan.cpp:39:10: fatal error: vulkan/vk_platform.h: No such file or directory 22:14 < bridge> 39 | #include ` 22:14 < bridge> now this 😂 22:14 < bridge> we could use msys2 on the CI as well. that’d get us the most up to date everything (even if it means we have to wait for a windows runner) 22:14 < bridge> Need to install Vulkan SDK separately 22:15 < bridge> yeah, would be good to also have the MSYS2 workflow tested separately 22:15 < bridge> msvc better 22:17 < bridge> ok i disabled vulkan from cmake and seems to work 22:17 < bridge> have same errors as you do now 23:05 < bridge> why does windows has 10 functions doing the same thing... 23:16 < bridge> what function 23:17 < bridge> RoActivateInstance same thing as ActivateInstance 23:17 < bridge> RoActivateInstance same thing as Windows::Foundation::ActivateInstance 23:51 < bridge> @robyt3 you can test again 23:51 < bridge> should be working now