Sorry your browser is not supported!

You are using an outdated browser that does not support modern web technologies, in order to use this site please update to a new browser.

Browsers supported include Chrome, FireFox, Safari, Opera, Internet Explorer 10+ or Microsoft Edge.

Newcomers DBPro Corner / [Tutorial] Easy collision system using sparky’s dll, with jumping, movement, including first and third person viewing.

Author
Message
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 13th Sep 2007 14:31 Edited at: 24th Sep 2007 12:26
Hello and thank you for taking the time to read my first ever tutorial.
This tutorial will teach the intermediate user how to make an easy collision system
using sparky’s dll, with jumping, movement, including first and third person viewing.
Perfect for starting any 3d game, and very easy to build upon.

Before any confusion, I will make this clear. This is an excerpt, condensed form, snippet,
call it what you like ; from the “Sliding collision” sparky’s dll demo. The instructions on top,
code at bottom. If any part needs more explaining in detail, ask.

If an algorithm looks weird to you, keep in mind that all this is in a loop.

Step 1
Ok, to start us off, this is the generic code you usually see at the start of many programs,
and if you don’t know what this does, read a few more tutorials before you try collision =P.
Heres a quick reminder of ‘autocam off’.
Autocam off : when you create a new object, the camera is automatically centered on it.
We don’t want this auto reaction, so we obviously turn it off.


Step 2
Just a few variable declarations, we use the radius for convenience, as the player is a sphere.
The rest is pretty self explanatory, if you don’t understand it don’t worry, you will later.


Step 3
makeLevel: load object is the loading of the actual 3d world you want to test
(swap ‘world.x’ with yours) and sc_setupcomplexobject is just setting up collision for this
3d model, and the reason its ‘complex’ is because if your model only contains less than 30-40 polys,
you would only use the sc_setupobject command but if it has more, the ‘complex’ one is a lot better
(makes it faster!).
The parameters for sc_setupcomplexobject are [object number, group(just leave this at one for the
moment),faces per node(I don’t pretend to know what this means, but the recommendation is that I
leave this at two, and that’s perfectly fine by me)]

makePlayer: This just gives us a sphere as a player, positions him at the center and slightly above
ground, and sets him up for collision. Note we use only sc_setupobject here, as its sufficient for the
amount of polys the sphere has.
Parameters for sc_setupobject – (objectnumber, group, type of collision(0-polygon 1-sphere 2-box –
Ok, usually you would leave this at 0 but since we are only setting up a sphere, we don’t need more
than a sphere collision)

A quick rundown  use sc_setupobject or sc_setupcomplexobject for any objects you want to have
collision with.


Step 4
Ok, this is the big one. Get ready.
Here is the whole code of the moveplayer sequence, we will break it up into chunks.



This is pretty self explanatory, it just rotates the camera, fps style, using the mouse.
Look at it for a while if you don’t get it, its just basic math.



Heres a big chunk, the movement part.
Keep the variable declarations in mind, they will become important later on.
Don’t bother trying to understand how the trig movement works if you cant be bothered, I opened
up a whole thread about it.
I will explain one crucial line of the code:
if vy#=0 and jumptimer=0 then vy# = vy# + 10*gravity# else vy# = vy# + gravity#
This means that if your jump has finished (y position returned to previous) and the timer between
jumps is zero, then stick player to ground (apply heavy gravity), or if youre still jumping apply normal
gravity.
The rest of the code is pretty self explanatory.
So this is pretty much movement before collision.




Ok this is the headache.
Ill explain it line by line.
The first line checks collision by casting a sphere down from the first position (oldx#,oldy#,oldz#)
to the second position (oldx#,oldy#+vy#).
An exact definition:
SC_sphereCastGroup

SYNTAX
return integer=SC_sphereCastGroup ( groupNum, oldx, oldy, oldz, x, y, z, radius, excludeObj )

-groupNum: the object you want to check for collision use 0 for all objects
-oldx...z: the start and end points of the sphere to check.
-radius: the radius of the sphere you want to cast.
-excludeObj: an object to exclude from the collision check.
returns: the object number collided with first is returned
returns 0 if no collision occured.

Similar to SC_sphereCast, except it checks groups of objects. see SC_sphereCast


Objects assigned group 0 during setup have no group and are ignored in group checks.


As you can see here, were only checking y collisions for now. Sliding comes a little later on.
Theres a few things you need to understand here. I have put it in a diagram.





So if our player collides against something, we first check the normal(rotation) of the polygon we
have collided against using sc_getcollisionnormalY(), assigning it the float ny#.


So if the positive ( abs() < the reason its positive is so you also slide when you jump against a
‘slopey’ roof.) rotation of the polygon is more than our slope (which at 0.5 is pretty steep), we set
oldy# to where sparky says we should place our object using sc_getStaticcollisionY(). This simulates
walking around on contoured hills etc.

But if the polygon we hit’s y rotation is more than our designated slope, we slide.
This part is easy, the ‘x# = x# - oldx# : z# = z# - oldz#’ nullifies the previous movement we made,
as the only thing we can currently do is slide. Sparky tells us where to put our object with
sc_getCollisionSlideX() ,Y, and Z. Then we fix up the variables again with
‘x# = x# + oldx# : z# = z# + oldz#’

The next little bit is self explanatory, so the ‘ground’ variable (used for jumping) is only activated if
youre on flat (not really flat, just above your slope) ground. Note, the value is not calculated as a positive,
as we cant really stand on anything below a vertical polygon (not that we can even stand on a
vertical polygon!), as it would be a ceiling. The vy# is set to zero, as we don’t need gravity to pull us
down when were already on flat ground. Whereas if what we collide on is less that negative slope (-0.5 in this case),
it would be treated as a ceiling and all upward movement is stopped. So what would happen if the
normal was within our negative slope? Well then we would be sliding up, as mentioned before
(think about it). Lastly, if we are not colliding against anything, we add downward speed and nullify
the ground variable.






This is your generic, but essential, sliding collision code,
It checks the X and Y variables. As you can see, sparky does all the work for you by giving you the new
sliding collision coordinates.


SC_sphereSlideGroup

SYNTAX
return integer=SC_sphereSlideGroup ( groupNum, oldx, oldy, oldz, x, y, z, radius, excludeObj )

-groupNum: the group you want to check for collision use 0 for all groups
-oldx...z: the start and end points of the sphere to check.
-radius: the radius of the sphere you want to cast.
-excludeObj: an object to exclude from the collision check.
returns: the object number collided with is returned
returns 0 if no collision occured.

Similar to SC_sphereSlide except it checks a group of objects
or all groups if group=0.

Objects assigned group 0 during setup have no group and are ignored in group collision.





Step 5
This is a pretty handy chunk of code to control the camera.
If you want to limit how far down you can look,
Put this just below the

part.




Step 6
And here we have our main loop.

The change view section with the times just mean this : instead of changing the variable at the
keypress using “if inkey$() = “whatever” then view = 1-view”, we use a timer, as in a fast loop the
variable will keep changing which will cause much inconvenience.
So if you take a quick look at it again, you will see that the timer (which decreases by itself) is reset
with each change.

The rest is pretty self explanatory….text for convenience….camera control….’q’ to quit…. And shift
to reset your position.




Step 6
And here we have the entire piece of code.



Give yourself a pat on the back if you managed to read the whole thing without getting hopelessly
confused.
Forgive me if this tutorial was incomprehensible, as it was my first tutorial. =)

Thank you once again!

Low poly fractal terrain
This will create some good looking low poly fractal terrain using this dll by el Goorf, and will convert it into
an object using this function by Lost in Thought, then set it up with sparky for collision.
Just put in the code in these sections-
Makelevel:


End of code:


Timer Based Movement
This is in relation to this code snippet

This is from jeffhuys.
replace the

With


(after doing "tm_init()" in the start of code and "t# = tm_update()" every cycle!
To move slower, change the 30 into 40.

Examples
This excellent one from jeffhuys also includes a cool effect called
adrenaline - press 'x' ingame an youll see.
http://forumfiles.thegamecreators.com/?i=1303047

Kaitia
17
Years of Service
User Offline
Joined: 8th Sep 2007
Location:
Posted: 13th Sep 2007 23:07 Edited at: 6th Oct 2007 23:07
omfg THANK YOU SO
MUCH I LOVE U!!!!!!!!!

Childish post edited by a mod!

''To program or not to program that is the question''
Kaitia
17
Years of Service
User Offline
Joined: 8th Sep 2007
Location:
Posted: 13th Sep 2007 23:11 Edited at: 6th Oct 2007 23:08
well... what im actually trying to say is that its quite OK..........
.....................................................................
....well screw it anyway THANK YOU SOSOSOSOSOSOSOSOSOSOSOSOSO--------MUCH-------

Mod edited another one!

''To program or not to program that is the question''
Kaitia
17
Years of Service
User Offline
Joined: 8th Sep 2007
Location:
Posted: 13th Sep 2007 23:12
But in step 3 you say load image blablabla but i dont got a image how do i get such world i mean you need to save it b4 you can load it right?

''To program or not to program that is the question''
Tom J
19
Years of Service
User Offline
Joined: 4th Aug 2005
Location: Essex, England
Posted: 13th Sep 2007 23:59 Edited at: 13th Sep 2007 23:59
Cool I've always been an NGC user up to now so this tutorial should be pretty helpful for learning more about doing sliding collision
with Sparky's. I'll try it out later, I'm busy right now Congratulations on your 1st (I think) tutorial!

@ Kaitia, ummm... your message has made the page very very very long, I don't suppose you could edit the message and shorten it a bit?

Code Dragon
18
Years of Service
User Offline
Joined: 21st Aug 2006
Location: Everywhere
Posted: 14th Sep 2007 02:42
Nice one

Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 14th Sep 2007 08:53 Edited at: 14th Sep 2007 09:01
Whoa i didnt think anybody would think it any good!
Thank you


@ kaitia - yeah youre right about the image, i was previously using it to texture the 3d object but obviously its unnecessary in this tut, so i havee removed it. thanks

EDIT: just realise how wide the text in the tut is - need to do some word wrapping.

EDIT 2: There we go, all word wrapped. and katia, could you lessen on the SOSOSO s? I really appreciate it though.

Kaitia
17
Years of Service
User Offline
Joined: 8th Sep 2007
Location:
Posted: 14th Sep 2007 17:27
you know.. so much but than like SO SO SO SO SO much
u know sosososososososo ^^

''To program or not to program that is the question''
Insert Name Here
17
Years of Service
User Offline
Joined: 20th Mar 2007
Location: Worcester, England
Posted: 14th Sep 2007 18:49
Shorten the text!!!!! Shorten!!!!! It's lengthend the page to... infinity!
Please don't spam either please.

............................
jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 17th Sep 2007 08:48
How to make that when you go up too much it stops the camera?

Legend of The Beast WIP...
You're the 'th to view this signature!
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 17th Sep 2007 09:10
Put this just below the

part.

if object angle x(2)>90 then xrotate object 2,90

jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 17th Sep 2007 09:15
Thanks!
PS: Nice tut!!!!

Legend of The Beast WIP...
You're the 'th to view this signature!
Kenn
18
Years of Service
User Offline
Joined: 25th Dec 2005
Location: PHILADELPHIA, USA
Posted: 18th Sep 2007 01:09
its about freakin time, all those nerd retards telling people to learn for themselves as if that is the way you teach a human being. You show more class then most of these experts.
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 18th Sep 2007 02:57 Edited at: 18th Sep 2007 02:58
Thank you Kenn, but i think those 'nerd retards' do want to help people, only sometimes newbies tend to not try to help themselves first.

EDIT : spelling

RUCCUS
19
Years of Service
User Offline
Joined: 11th Dec 2004
Location: Canada
Posted: 18th Sep 2007 03:08
Kenn, what are you talking about? There's been tutorials on collision out on these forums for years, and there's even that "massive collision resource" thread I made a year ago packed with all the collision info you could need (and soon a link to this thread).

Aralox, great tut, gona add it to the massive collision thread after this.

Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 18th Sep 2007 03:15
Thanks RUCCUS, and i must say, i love your sigs!
They always seem to be changing!
what image editor do you use for em?

jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 20th Sep 2007 17:37 Edited at: 21st Sep 2007 16:24
Hey Aralox!
Is there a way to put this timer based movement into your code?
I tried it, but with those sin's and cos's...
Thanks!

EDIT: I've done it! It is not that hard, just replace the

With
.
(after doing "tm_init()" in the start of code and "t# = tm_update()" every cycle)
To move slower, change the 30 into 40.


EDIT2: I only still don't know how to implement it in the jumping... Someone try it?

-Jeff

Legend of The Beast WIP...
You're the 'th to view this signature!
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 21st Sep 2007 08:39
Nice work Jeff! Ill put that up in the first post.

jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 21st Sep 2007 16:28 Edited at: 21st Sep 2007 22:37
Thanks!
I love it when someone likes my code!

EDIT: I've added something VERY cool! I call it "Adrenaline". Download the .EXE in the bottom right corner to see. (I have added a simple level of 3D World Studio, and I've added a sky.)

-Press X to toggle adrenaline.
The rest is logic.

HAVE FUN!

EDIT2: Here is a direct link because of that stupid page stretch!

-Jeff

Legend of The Beast WIP...
You're the 'th to view this signature!

Attachments

Login to view attachments
Kenn
18
Years of Service
User Offline
Joined: 25th Dec 2005
Location: PHILADELPHIA, USA
Posted: 22nd Sep 2007 04:12
Kaitia please your breaking the tables and your making it hard to read please delete the "SOSO". Artards
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 22nd Sep 2007 04:58
That is indeed awesome jeff!
I love the adrenaline effect! do you mind if i use it in my game?
This is going up in the first post too.

To everyone else, until kaitia edits her message, an easy way to get rid of the stretch is to toggle her messages.

jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 22nd Sep 2007 13:01 Edited at: 22nd Sep 2007 14:27
@Aralox: No problem mate If you want the source, just ask!
I've added a counter for it too, and added an heartbeat sound when adrenaline is used!
Now for the most difficult part: THE GUN!
I have NO IDEA how to implement this... You?

-Jeff

Legend of The Beast WIP...
You're the 'th to view this signature!
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 23rd Sep 2007 06:36
Ive been working on Roborb for a while now, and i have come up with a system for guns.
If i were you, i would opt for the easy method and go for the intersection(look on the forums), but the method im trying is different functions for different types of guns, where the first gun im doing (AK-45 sort of thing) fires a stream of bullets and casts a ray between each bullet point. Im not sure if this is done before but i like this method.

Just look around on the forums for a better explained way to do guns, there are tuts everywhere.

jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 23rd Sep 2007 11:48 Edited at: 23rd Sep 2007 12:16
Quote: "Just look around on the forums for a better explained way to do guns, there are tuts everywhere."

I will, thanks!

PS: shouldn't we post this in the code snippets too? I mean, there are the most people looking for things like this...


You're the 'th to view this signature!

Attachments

Login to view attachments
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 23rd Sep 2007 11:54
I guess i should, but i think this will help the newbie board alot more than it does the code snippet one.
Besides, this is a tutorial, not just a snippet.

jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 23rd Sep 2007 12:09 Edited at: 23rd Sep 2007 12:16
True. I think if a mod sees this he could consider to sticky this, as this is a very helpful topic!

Jeff


You're the 'th to view this signature!

Attachments

Login to view attachments
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 24th Sep 2007 12:25
Check out the new code example - low poly fractal terrain w/ sparkys!

jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 24th Sep 2007 17:21
Cool! And the fps is nice!
I am still trying to get the gun working... It is a bit hard...

-Jeff


You're the 'th to view this signature!
jeffhuys
18
Years of Service
User Offline
Joined: 24th May 2006
Location: No cheesy line here.
Posted: 13th Oct 2007 18:22
Why isn't this getting attention anymore?
And thanks mod for that post edit

-Jeff


You're the 'th to view this signature!
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 14th Oct 2007 01:24
I hope people are still finding this useful, and now that its on Zotoaster's Sticky-ed Tutorials thread in this board, im sure this will always be useful to someone.

xCept
21
Years of Service
User Offline
Joined: 15th Dec 2002
Location:
Posted: 15th Oct 2007 00:34
Hi,

Thanks for writing this tutorial. I have been using Sparky's Collision for some time, and after testing out many other collision methods and DLLs I really prefer Sparky's to any other.

The one big problem I do have, and maybe one that you or someone else could help me with, is...

The collision works fine if the player object is one of the DB primitives (a sphere, a box, etc.) but if I load in an actual 3D object (.X or .3DS), even if the model is just a simple box, the collision is completely off and half of the player goes right through the level before collision is detected. I've tried switching the collision type to polygons, to complexObject, etc., and nothing seems to help. It's as if the collision box for the object is halfway beneath the character, and when it "lands" on the ground it is still half floating in the air.

Here is a screenshot of a model box and how the collision looks in a simple level. I can also include a demonstration project if needed, but I really would like to get this fixed or I can't use Sparky's Collision in any real projects.

Thanks!

Attachments

Login to view attachments
Gero Fox
17
Years of Service
User Offline
Joined: 28th Sep 2007
Location: Saudi,Damam
Posted: 16th Oct 2007 07:23
Thanks I like thats construing
I want to

or


and stop if up press key please


I like eating the pizza and drinking coffee some time^^
I want to learn DBPro
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 16th Oct 2007 12:55
xCept firstly, do you have the latest version of dbp?
If you do, then what program are you using to create your models?
Then only time i have encountered something like this is when i move my objects around without sc_update-ing them.
One thing you could do is to add a certain amount to the repositioning command at the end of the controls, but i would count this only temporary until the problem is fully resolved.

And Gero Fox, im not going to give you code, but i would suggest reading up the inkey$ command. the rest of it is just ifs and thens.

xCept
21
Years of Service
User Offline
Joined: 15th Dec 2002
Location:
Posted: 16th Oct 2007 21:09
I'm using DBPro 6.6, Sparky's Collision 2.02, and I've tried the default IDE and CodeSurge without any luck. I've used older versions in the past, and have always had this issue. I have tried using 3DS Max (exported as .X and .3DS) and a friend sent me a model exported through Cinema 4D, still the same problem occurs.

Attached is a test project which contains a simple .X level, .X box character, and the source which is a slightly modified version of the tutorial example. Any help would be much appreciated.

Attachments

Login to view attachments
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 18th Oct 2007 12:58
I tested it out, and what i got is that the collision is registering slightly lower than where the model actually is. This happens for both your player model and your level model ( i can tell because when i use d your remmed out make box code the box was actually colliding fine).
This leads me to believe that there is something slightly wrong with your modelling software, or at least the exporter you use for it.

xCept
21
Years of Service
User Offline
Joined: 15th Dec 2002
Location:
Posted: 18th Oct 2007 18:31
Thanks. Well, I've used three different exporters and messed around with many different settings, still no luck. What do you use to export models, and would it be possible for you to post an example with working collision using an imported .X model?
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 19th Oct 2007 08:47
Well i do my modelling in C4D which has its own .x exporter, and if you want an example check out my extreme alpha of roborb. the game has improved massively from the example, but im taking a break from programming.

xCept
21
Years of Service
User Offline
Joined: 15th Dec 2002
Location:
Posted: 19th Oct 2007 09:12
I get a "File Not Found" error when I try to download your alpha, or even view any of its screenshots.
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 19th Oct 2007 10:05
arrgh i just remembered that all my files are down!
Cant be bothered putting them up right now...

icenine
17
Years of Service
User Offline
Joined: 11th Jan 2007
Location: Philippines
Posted: 22nd Oct 2007 13:22
Hello..
im having trouble in working codes. my question is, if i create a new object there is no collision to the map. only the player has a collision to the map.. how am i gonna add collision to the other object. ive used aralox code.. is the code gonna be more longer?

Attachments

Login to view attachments
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 23rd Oct 2007 10:29
How would you be able to tell if the map has no collision?
If you fell right through you wouldnt know if it was the player or the map thats the problem.

icenine
17
Years of Service
User Offline
Joined: 11th Jan 2007
Location: Philippines
Posted: 4th Nov 2007 08:27
what i meant was , ive created another object... and that object has no collision to the map... if i apply collision and gravity to that object the code might be more longer.. is there a way were i can insert it somewhere
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 4th Nov 2007 22:46
Yes of course, havent you actually read the tutorial and not just copy the code?

ill give you a hint

sc_setup[complex]object.....

prepe
17
Years of Service
User Offline
Joined: 26th Feb 2007
Location: phx. az.
Posted: 10th Nov 2007 07:21
It says it dose not understand 'sc_setupComplexObject 1,1,2'
Did i do something rong?

Prepe

Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 11th Nov 2007 04:59
setupcomplexobject [the object you want to set up] , [group] , 2

prepe
17
Years of Service
User Offline
Joined: 26th Feb 2007
Location: phx. az.
Posted: 11th Nov 2007 10:49 Edited at: 11th Nov 2007 10:53
Yeah its not working. I have it set up like this.



Did i do it right, or mabby I miss read?

Mabby I put the .dll in the rong spot? Where dose it go exactly?

Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 11th Nov 2007 23:16
in the plugins-user folder.

youve done it right as far as i can see.

riskbreaker 85
17
Years of Service
User Offline
Joined: 13th Mar 2007
Location:
Posted: 27th Nov 2007 08:35
hello

is there a way if i can load a map using .dbo file instead of a .x file??

im having trouble with layered textures and entities if i export it to .x. it just wont show in the game.

im using 3d world studio.. should i switch a map editor?

tnx
Aralox
17
Years of Service
User Offline
Joined: 16th Jan 2007
Location: Melbourne
Posted: 27th Nov 2007 10:40
You certainly can use a .dbo file for collision, sparkys applies to the object created from the file, not the file itself.

r3d3y35
16
Years of Service
User Offline
Joined: 6th Dec 2007
Location: Canada
Posted: 8th Dec 2007 04:09
im having trouble implementing the timer based movement code in, im not exactly sure where to put the functions, whenever i put the anywhere besides the end i get an error message

Login to post a reply

Server time is: 2024-11-25 09:41:42
Your offset time is: 2024-11-25 09:41:42