2022-12-30 17:04:27 +01:00
require " uri "
require " base64 "
include CrystalGauntlet
2023-01-03 08:02:50 +01:00
CrystalGauntlet . endpoints [ " /downloadGJLevel22.php " ] = - > ( context : HTTP :: Server :: Context ) : String {
params = URI :: Params . parse ( context . request . body . not_nil! . gets_to_end )
2023-01-02 11:59:37 +01:00
LOG . debug { params . inspect }
2022-12-30 17:04:27 +01:00
2023-01-02 13:21:49 +01:00
response = [ ] of String
2022-12-30 17:04:27 +01:00
2023-01-04 00:20:45 +01:00
level_id = params [ " levelID " ] . to_i32
daily_num = nil # for hash checks
case level_id
when - 1
# daily
level_id , _ , idx = Dailies . fetch_current_level ( false )
if ! level_id || ! idx
return " -1 "
end
daily_num = idx
when - 2
# weekly
level_id , _ , idx = Dailies . fetch_current_level ( true )
if ! level_id || ! idx
return " -1 "
end
daily_num = idx + Dailies :: WEEKLY_OFFSET
when - 3
# events
raise " events?? what the hell "
end
2023-01-07 12:57:18 +01:00
level_exists = false
2023-01-05 20:44:02 +01:00
DATABASE . query ( " select levels.id, levels.name, levels.extra_data, levels.level_info, levels.password, levels.user_id, levels.description, levels.original, levels.game_version, levels.requested_stars, levels.version, levels.song_id, levels.length, levels.objects, levels.coins, levels.has_ldm, levels.two_player, levels.downloads, levels.likes, levels.difficulty, levels.community_difficulty, levels.demon_difficulty, levels.stars, levels.featured, levels.epic, levels.rated_coins, levels.created_at, levels.modified_at, users.username, users.udid, users.account_id, users.registered, editor_time, editor_time_copies from levels join users on levels.user_id = users.id where levels.id = ? " , level_id ) do | rs |
2022-12-30 17:04:27 +01:00
if rs . move_next
id = rs . read ( Int32 )
name = rs . read ( String )
extra_data = rs . read ( String )
level_info = rs . read ( String )
password = rs . read ( String | Nil )
user_id = rs . read ( Int32 )
description = rs . read ( String )
original = rs . read ( Int32 | Nil )
game_version = rs . read ( Int32 )
requested_stars = rs . read ( Int32 | Nil )
version = rs . read ( Int32 )
song_id = rs . read ( Int32 )
length = rs . read ( Int32 )
objects = rs . read ( Int32 )
coins = rs . read ( Int32 )
has_ldm = rs . read ( Bool )
two_player = rs . read ( Bool )
downloads = rs . read ( Int32 )
likes = rs . read ( Int32 )
2022-12-31 07:59:44 +01:00
set_difficulty_int = rs . read ( Int32 | Nil )
set_difficulty = set_difficulty_int && LevelDifficulty . new ( set_difficulty_int )
community_difficulty_int = rs . read ( Int32 | Nil )
community_difficulty = community_difficulty_int && LevelDifficulty . new ( community_difficulty_int )
difficulty = set_difficulty || community_difficulty
2022-12-30 17:04:27 +01:00
demon_difficulty_int = rs . read ( Int32 | Nil )
demon_difficulty = demon_difficulty_int && DemonDifficulty . new ( demon_difficulty_int )
stars = rs . read ( Int32 | Nil )
featured = rs . read ( Bool )
epic = rs . read ( Bool )
rated_coins = rs . read ( Bool )
2023-01-05 20:44:02 +01:00
created_at = rs . read ( String )
updated_at = rs . read ( String )
2022-12-30 17:04:27 +01:00
user_username = rs . read ( String )
user_udid = rs . read ( String | Nil )
user_account_id = rs . read ( Int32 | Nil )
user_registered = rs . read ( Bool )
2023-01-03 12:42:18 +01:00
editor_time = rs . read ( Int32 )
editor_time_copies = rs . read ( Int32 )
2023-01-03 06:58:24 +01:00
2022-12-30 17:04:27 +01:00
xor_pass = " 0 "
if ! password
password = " 0 "
2023-01-07 16:25:32 +01:00
elsif Versions . parse ( params [ " gameVersion " ]? || " 19 " ) >= Versions :: V2_0
2023-01-03 11:38:23 +01:00
xor_pass = Base64 . urlsafe_encode ( XorCrypt . encrypt_string ( password , " 26364 " ) )
2022-12-30 17:04:27 +01:00
else
xor_pass = password
end
2023-01-08 09:00:30 +01:00
if Versions . parse ( params [ " gameVersion " ]? || " 19 " ) >= Versions :: V2_0
description = Base64 . urlsafe_encode ( description )
end
2023-01-05 15:08:57 +01:00
level_data = Base64 . urlsafe_encode ( File . read ( DATA_FOLDER / " levels " / " #{ id } .lvl " ) )
2023-01-03 12:42:18 +01:00
2023-01-02 13:12:41 +01:00
# todo: deduplicate this with getLevels?
2023-01-02 13:21:49 +01:00
response << CrystalGauntlet :: Format . fmt_hash ( {
2022-12-30 17:04:27 +01:00
1 = > id ,
2 = > name ,
2023-01-07 16:25:32 +01:00
3 = > description ,
2022-12-30 17:04:27 +01:00
4 = > level_data ,
5 = > version ,
6 = > user_id ,
2023-01-03 06:58:24 +01:00
# this is suppoused to be the amount of people who have
# voted on a level, but this is unused by the game, so
# we just always tell the game 10 people have voted
2022-12-30 17:04:27 +01:00
8 = > 10 ,
2023-01-03 06:58:24 +01:00
# 0=N/A 10=EASY 20=NORMAL 30=HARD 40=HARDER 50=INSANE 50=AUTO 50=DEMON
# divided by above value, which is why its multiplied by 10
9 = > ( difficulty ? difficulty . to_star_difficulty : 0 ) . not_nil! * 10 ,
2023-01-07 12:57:18 +01:00
10 = > downloads + 1 ,
2022-12-31 14:25:43 +01:00
12 = > ! Songs . is_custom_song ( song_id ) ? song_id : 0 ,
2022-12-30 17:04:27 +01:00
13 = > game_version ,
2023-01-03 06:58:24 +01:00
# likes - dislikes
2022-12-30 17:04:27 +01:00
14 = > likes ,
2023-01-03 06:58:24 +01:00
# dislikes - likes
16 = > - likes ,
15 = > length ,
2022-12-30 17:04:27 +01:00
17 = > difficulty && difficulty . demon? ,
18 = > stars || 0 ,
19 = > featured ,
2023-01-03 06:58:24 +01:00
25 = > difficulty && difficulty . auto? ,
27 = > xor_pass ,
2023-01-05 20:44:02 +01:00
28 = > Time . parse ( created_at , Format :: TIME_FORMAT , Time :: Location :: UTC ) ,
29 = > Time . parse ( updated_at , Format :: TIME_FORMAT , Time :: Location :: UTC ) ,
2023-01-03 06:58:24 +01:00
30 = > original || 0 ,
31 = > two_player , 26 = > params . has_key? ( " extras " ) ? level_info : nil ,
2022-12-31 14:25:43 +01:00
35 = > Songs . is_custom_song ( song_id ) ? song_id : 0 ,
2022-12-30 17:04:27 +01:00
36 = > extra_data ,
37 = > coins ,
38 = > rated_coins ,
39 = > requested_stars || 0 ,
40 = > has_ldm ,
2023-01-04 00:20:45 +01:00
41 = > daily_num ,
2023-01-03 06:58:24 +01:00
42 = > epic ,
# 0 for n/a, 10 for easy, 20, for medium, ...
43 = > ( demon_difficulty || DemonDifficulty :: Hard ) . to_demon_difficulty ,
# todo
44 = > false ,
45 = > objects ,
2023-01-03 07:14:02 +01:00
46 = > editor_time ,
47 = > editor_time_copies
2022-12-30 17:04:27 +01:00
} )
2023-01-02 13:21:49 +01:00
response << Hashes . gen_solo ( level_data )
2022-12-30 17:04:27 +01:00
2023-01-04 00:20:45 +01:00
thing = [ user_id , stars || 0 , ( difficulty && difficulty . demon? ) || 0 , id , rated_coins , featured , password , daily_num || 0 ] . map { | x | Format . fmt_value ( x ) }
2023-01-02 13:21:49 +01:00
response << Hashes . gen_solo_2 ( thing . join ( " , " ) )
2023-01-04 00:20:45 +01:00
if daily_num
response << [ user_id , user_username , user_account_id ] . join ( " : " )
end
2023-01-07 12:57:18 +01:00
level_exists = true
2022-12-30 17:04:27 +01:00
else
2023-01-07 12:57:18 +01:00
response << " -1 "
2022-12-30 17:04:27 +01:00
end
end
2023-01-07 12:57:18 +01:00
2023-01-07 15:34:41 +01:00
if level_exists
2023-01-07 17:31:40 +01:00
ip = IPs . get_real_ip ( context . request )
if DATABASE . scalar ( " select count(*) from ip_actions where action = ? and value = ? and ip = ? limit 1 " , " download " , level_id , ip ) . as? ( Int64 ) == 0
DATABASE . exec ( " update levels set downloads = downloads + 1 where id = ? " , level_id )
DATABASE . exec ( " insert into ip_actions (action, value, ip) values (?, ?, ?) " , " download " , level_id , ip )
2023-01-21 20:44:21 +01:00
downloads = DATABASE . scalar ( " select downloads from levels where id = ? " , level_id ) . as ( Int64 )
if downloads == 300
# notify the creator of 300 downloads
account_id , level_name = DATABASE . query_one ( " select users.account_id, levels.name from levels left join users on users.id = levels.user_id where levels.id = ? " , level_id , as : { Int32 ?, String } )
if account_id
if DATABASE . scalar ( " select count(*) from notifications where type = \" download_milestone \" and target = ? and account_id = ? " , level_id , account_id ) . as ( Int64 ) == 0
Notifications . send_notification ( account_id , " download_milestone " , level_id , {
" level_name " = > level_name ,
" amount " = > downloads
} )
end
end
end
2023-01-07 17:31:40 +01:00
end
2023-01-07 12:57:18 +01:00
end
response . join ( " # " )
2022-12-30 17:04:27 +01:00
}
2023-01-07 14:34:09 +01:00
CrystalGauntlet . endpoints [ " /downloadGJLevel20.php " ] = CrystalGauntlet . endpoints [ " /downloadGJLevel22.php " ]
2023-01-07 16:25:32 +01:00
CrystalGauntlet . endpoints [ " /downloadGJLevel19.php " ] = CrystalGauntlet . endpoints [ " /downloadGJLevel22.php " ]