This blog post is related to my Google Summer of Code 2023 project .
-
Patch #2352 has been merged
which provides:
- Implementation for
json_encode()
user function. - SOG (Single Object Game) file is written for testing the function.
- Implementation for
Solving 7+ days problem...
There is a problem with string passed to the event map. it contains weird stream of text. This
text is actually a DEBUG
messages that I created for debugging purposes.
I actually need only the blue data but the rest is undefined behavior. Look what is the interesting part, before accumulating anything inside the string, it's fine and empty. But after accumulating even a single bracket, it starts to contains that concatenated DEBUG messages.
I didn't faced something like this before, so Jsoh resommended to use
Valgrind, TSAN
, and ASAN
to find
the problem.
two possibilities:
- Someone is stashing a pointer to that string somewhere out-of-thread
- You have a buffer overflow somewhere and are facing memory corruption
try building your code with TSAN/ASAN enabled to see if you can detect that
if you're on Linux, another option is Valgrind; it will find everything wrong, but will slow the code to a crawl, so make sure you can reproduce the problem quickly and easily
these are good tools to have under your belt and will help you later
cool; make sure the game is built with debugging symbols (-g) so Valgrind output will be useful
set the "mode" var to DEBUG for ENIGMA's make system
Josh — 13/08/2023 18:15
Now that's a higher level of debugging and we are diverging. I started using Valgrind and by the way found a small memory leak in ENIGMA, that can be very annoying when working for long periods which explains why it was freezing my 8GB Virtual Machine.
I have got this output right after the RequestCurrentStats
succeeded.
Notice that the start_thread
? and the enigma::ENIGMA_events()
? That
looks like the problem is here. Another thing is that the gameoverlayrenderer.so
library which is responsible for rendering the Steam overlay is also involved. Actually this
enigma::ENIGMA_events
function is generated by the compiler, I mean I can't
debug it directly. I have to debug the code that generates it which is the compiler itself.
The next output is after closing the running exmaple game, it's the summary of the
Valgrind
output. Let's keep it here for reference.
Even though I don't know what is the problem and can't understand what is going on in
Valgrind output, but the problem is with concatenating
strings over and over to create the Async output format. Josh then recommended to use
stringstream
instead of std::string
to concatenate strings. I tried
this but as always didn't work.
An idea came to mind to try to concatenate outside the function, just after the
sstream
definition. I started with only writing a single bracket:
I viewed the string using leaderboard_entries_buffer.str()
and it's very
clean!!!. I tried then concatenating the whole string outside the function and it again
failed. I remember that even the first line was failing before and now it's working!!!
Why? Wait a second that's my first trial inside the function:
Notice the difference? It's the concatenation operator. When using sstream
,
you have to use <<
. However when using normal std::string
you
can use +=
or .append()
method. They both have the same effect.
Now I know what to do, let's test my theory. Let's remove every +=
and
replace it with <<
. I did that and it worked!!! 🎉 🎉
🎉.
This is not reasonable anyway but it's a solution. I will wait for an explanation from my mentors about this. Here's the final output:
It's just the lb_name
is empty but it's a simple issue we can fix later. Let's move
to the next phase.
More diverging...
There are two important TODOs that must be done here which are:
-
Updating my patch #2352
to use
sstream
instead ofstd::string
. -
For functions such as
steam_download_scores
, withid
to be saved for each download request, I will use the new ENIGMA's approach for that with is:AssetArray
fromUniversal System
. - Implementing a new draw function for drawing leaderboards.
-
Get this done:
@Saif print that debug message three times and I'll bet you it looks different every time
you seem to be seeing stream contamination, not actual memory corruption; I'm guessing your memory is fine
print the string to a file instead if you want to see it unmolested
Josh — 14/08/2023 17:50
This patch #2353 solves the first TODO.
Let's move to the second TODO. I will use the AssetArray
to save the id for each
download request made by the player. In order to do that, I will follow simple approach of
preventing any requests as long as we have a pending request. The tricky part here is that
when we are ready to accpet a new request? Well, when we save the entries we got in the
AssetArray
, we are ready. So set the loading_
to false
after saving the entries.
Working with AssetArray
is very easy. I guess now we are done with the second
TODO.
Another thing that I need to mention here is that GMS has a function called
instance_create_depth()
, while ENIGMA has instance_create()
and
depth
variable. I may provide a patch to combine them both as GMS does to
maintain compatibility. But for now I will just use instance_create()
and
set the depth manually.
Here's the TODO list again:
- Implementing a new draw function for drawing leaderboards.
-
Get this done:
@Saif print that debug message three times and I'll bet you it looks different every time
you seem to be seeing stream contamination, not actual memory corruption; I'm guessing your memory is fine
print the string to a file instead if you want to see it unmolested
Josh — 14/08/2023 17:50 - Implement
instance_create_depth()
user function.
Now the problem is with the json_decode()
user function. It took me the whole day
to find the problem which is bascially Json
extension doesn't convert the Json to
DS map correctly. It parses Jsons correctly and also the DataStructures
extension
working fine. The layer between them both is broken.
I provided Patch #2355 for issue #2354:
- Fixes
Json
extension not converting to DS map properly. - Wrote SOG file to test the changes.
- Renamed a SOG file which belongs to short Json PR (I renamed it to better naming while I am here).
After fixing the json_decode()
user function, the leaderboard entries started to
view some data. Here is the output:
Here is the GMS output:
Robert finished my 3rd TODO in patch #2356. I tested it and it's working fine. Besides that he talked to me about attaching the id of the download request to the Callback function somehow instead of saving it statically so I think we have got another TODO here.
- Implementing a new draw function for drawing leaderboards.
-
Get this done:
@Saif print that debug message three times and I'll bet you it looks different every time
you seem to be seeing stream contamination, not actual memory corruption; I'm guessing your memory is fine
print the string to a file instead if you want to see it unmolested
Josh — 14/08/2023 17:50 - Changing the way I save download requests' ids.
There is something wrong with Json extension again!!! The keys are there, but there values are contain garbage values like weird integers. I debugged the code and fixed the problem for the 100 time in patch #2357.
Now the Leaderboards API looks complete:
Here is the TODO for the next week:
- Implementing a new draw function for drawing leaderboards.
-
Get this done:
@Saif print that debug message three times and I'll bet you it looks different every time
you seem to be seeing stream contamination, not actual memory corruption; I'm guessing your memory is fine
print the string to a file instead if you want to see it unmolested
Josh — 14/08/2023 17:50 - Changing the way I save download requests' ids.
- Implement the rest APIs.
- Getting an
AppId
and upload a game on Steam for testing. - Creating SOGs and trying to make it work as I mentioned earlier that it's tricky because we need Steam to be running in order the tests to pass.
- Cleaning up and organizing the new Async System to match Robert's needs.
-
Checking if
Callbacks
uses Threads. If so then try to handle the State Management manually. - CPP source files need to be documented.
- Check the license for committing DLLs and headers.
- Check Steamworks's official example comments.
- Check GMS Manual for documenting user function's layer.
- Check Robert's PR #2349
-
Creating stub for Steamworks extension to take its place when disabled.
you need a stub for when the extension isnt enabled
its just an empty function
gfundies — 16/08/2023 10:44
add - Document and maintain
Json
extension. - Document and maintain
Asynchronous
system. - Explain the Steamworks extension's structure and what goes where.
instance_create_depth()
user function to the WIKI.