diff --git a/data/wordlist.txt b/data/wordlist.txt
new file mode 100644
index 000000000..fb0a9e35e
--- /dev/null
+++ b/data/wordlist.txt
@@ -0,0 +1,1296 @@
+1111 acid
+1112 acorn
+1113 acre
+1114 acts
+1115 afar
+1116 affix
+1121 aged
+1122 agent
+1123 agile
+1124 aging
+1125 agony
+1126 ahead
+1131 aide
+1132 aids
+1133 aim
+1134 ajar
+1135 alarm
+1136 alias
+1141 alibi
+1142 alien
+1143 alike
+1144 alive
+1145 aloe
+1146 aloft
+1151 aloha
+1152 alone
+1153 amend
+1154 amino
+1155 ample
+1156 amuse
+1161 angel
+1162 anger
+1163 angle
+1164 ankle
+1165 apple
+1166 april
+1211 apron
+1212 aqua
+1213 area
+1214 arena
+1215 argue
+1216 arise
+1221 armed
+1222 armor
+1223 army
+1224 aroma
+1225 array
+1226 arson
+1231 art
+1232 ashen
+1233 ashes
+1234 atlas
+1235 atom
+1236 attic
+1241 audio
+1242 avert
+1243 avoid
+1244 awake
+1245 award
+1246 awoke
+1251 axis
+1252 bacon
+1253 badge
+1254 bagel
+1255 baggy
+1256 baked
+1261 baker
+1262 balmy
+1263 banjo
+1264 barge
+1265 barn
+1266 bash
+1311 basil
+1312 bask
+1313 batch
+1314 bath
+1315 baton
+1316 bats
+1321 blade
+1322 blank
+1323 blast
+1324 blaze
+1325 bleak
+1326 blend
+1331 bless
+1332 blimp
+1333 blink
+1334 bloat
+1335 blob
+1336 blog
+1341 blot
+1342 blunt
+1343 blurt
+1344 blush
+1345 boast
+1346 boat
+1351 body
+1352 boil
+1353 bok
+1354 bolt
+1355 boned
+1356 boney
+1361 bonus
+1362 bony
+1363 book
+1364 booth
+1365 boots
+1366 boss
+1411 botch
+1412 both
+1413 boxer
+1414 breed
+1415 bribe
+1416 brick
+1421 bride
+1422 brim
+1423 bring
+1424 brink
+1425 brisk
+1426 broad
+1431 broil
+1432 broke
+1433 brook
+1434 broom
+1435 brush
+1436 buck
+1441 bud
+1442 buggy
+1443 bulge
+1444 bulk
+1445 bully
+1446 bunch
+1451 bunny
+1452 bunt
+1453 bush
+1454 bust
+1455 busy
+1456 buzz
+1461 cable
+1462 cache
+1463 cadet
+1464 cage
+1465 cake
+1466 calm
+1511 cameo
+1512 canal
+1513 candy
+1514 cane
+1515 canon
+1516 cape
+1521 card
+1522 cargo
+1523 carol
+1524 carry
+1525 carve
+1526 case
+1531 cash
+1532 cause
+1533 cedar
+1534 chain
+1535 chair
+1536 chant
+1541 chaos
+1542 charm
+1543 chase
+1544 cheek
+1545 cheer
+1546 chef
+1551 chess
+1552 chest
+1553 chew
+1554 chief
+1555 chili
+1556 chill
+1561 chip
+1562 chomp
+1563 chop
+1564 chow
+1565 chuck
+1566 chump
+1611 chunk
+1612 churn
+1613 chute
+1614 cider
+1615 cinch
+1616 city
+1621 civic
+1622 civil
+1623 clad
+1624 claim
+1625 clamp
+1626 clap
+1631 clash
+1632 clasp
+1633 class
+1634 claw
+1635 clay
+1636 clean
+1641 clear
+1642 cleat
+1643 cleft
+1644 clerk
+1645 click
+1646 cling
+1651 clink
+1652 clip
+1653 cloak
+1654 clock
+1655 clone
+1656 cloth
+1661 cloud
+1662 clump
+1663 coach
+1664 coast
+1665 coat
+1666 cod
+2111 coil
+2112 coke
+2113 cola
+2114 cold
+2115 colt
+2116 coma
+2121 come
+2122 comic
+2123 comma
+2124 cone
+2125 cope
+2126 copy
+2131 coral
+2132 cork
+2133 cost
+2134 cot
+2135 couch
+2136 cough
+2141 cover
+2142 cozy
+2143 craft
+2144 cramp
+2145 crane
+2146 crank
+2151 crate
+2152 crave
+2153 crawl
+2154 crazy
+2155 creme
+2156 crepe
+2161 crept
+2162 crib
+2163 cried
+2164 crisp
+2165 crook
+2166 crop
+2211 cross
+2212 crowd
+2213 crown
+2214 crumb
+2215 crush
+2216 crust
+2221 cub
+2222 cult
+2223 cupid
+2224 cure
+2225 curl
+2226 curry
+2231 curse
+2232 curve
+2233 curvy
+2234 cushy
+2235 cut
+2236 cycle
+2241 dab
+2242 dad
+2243 daily
+2244 dairy
+2245 daisy
+2246 dance
+2251 dandy
+2252 darn
+2253 dart
+2254 dash
+2255 data
+2256 date
+2261 dawn
+2262 deaf
+2263 deal
+2264 dean
+2265 debit
+2266 debt
+2311 debug
+2312 decaf
+2313 decal
+2314 decay
+2315 deck
+2316 decor
+2321 decoy
+2322 deed
+2323 delay
+2324 denim
+2325 dense
+2326 dent
+2331 depth
+2332 derby
+2333 desk
+2334 dial
+2335 diary
+2336 dice
+2341 dig
+2342 dill
+2343 dime
+2344 dimly
+2345 diner
+2346 dingy
+2351 disco
+2352 dish
+2353 disk
+2354 ditch
+2355 ditzy
+2356 dizzy
+2361 dock
+2362 dodge
+2363 doing
+2364 doll
+2365 dome
+2366 donor
+2411 donut
+2412 dose
+2413 dot
+2414 dove
+2415 down
+2416 dowry
+2421 doze
+2422 drab
+2423 drama
+2424 drank
+2425 draw
+2426 dress
+2431 dried
+2432 drift
+2433 drill
+2434 drive
+2435 drone
+2436 droop
+2441 drove
+2442 drown
+2443 drum
+2444 dry
+2445 duck
+2446 duct
+2451 dude
+2452 dug
+2453 duke
+2454 duo
+2455 dusk
+2456 dust
+2461 duty
+2462 dwarf
+2463 dwell
+2464 eagle
+2465 early
+2466 earth
+2511 easel
+2512 east
+2513 eaten
+2514 eats
+2515 ebay
+2516 ebony
+2521 ebook
+2522 echo
+2523 edge
+2524 eel
+2525 eject
+2526 elbow
+2531 elder
+2532 elf
+2533 elk
+2534 elm
+2535 elope
+2536 elude
+2541 elves
+2542 email
+2543 emit
+2544 empty
+2545 emu
+2546 enter
+2551 entry
+2552 envoy
+2553 equal
+2554 erase
+2555 error
+2556 erupt
+2561 essay
+2562 etch
+2563 evade
+2564 even
+2565 evict
+2566 evil
+2611 evoke
+2612 exact
+2613 exit
+2614 fable
+2615 faced
+2616 fact
+2621 fade
+2622 fall
+2623 false
+2624 fancy
+2625 fang
+2626 fax
+2631 feast
+2632 feed
+2633 femur
+2634 fence
+2635 fend
+2636 ferry
+2641 fetal
+2642 fetch
+2643 fever
+2644 fiber
+2645 fifth
+2646 fifty
+2651 film
+2652 filth
+2653 final
+2654 finch
+2655 fit
+2656 five
+2661 flag
+2662 flaky
+2663 flame
+2664 flap
+2665 flask
+2666 fled
+3111 flick
+3112 fling
+3113 flint
+3114 flip
+3115 flirt
+3116 float
+3121 flock
+3122 flop
+3123 floss
+3124 flyer
+3125 foam
+3126 foe
+3131 fog
+3132 foil
+3133 folic
+3134 folk
+3135 food
+3136 fool
+3141 found
+3142 fox
+3143 foyer
+3144 frail
+3145 frame
+3146 fray
+3151 fresh
+3152 fried
+3153 frill
+3154 frisk
+3155 from
+3156 front
+3161 frost
+3162 froth
+3163 frown
+3164 froze
+3165 fruit
+3166 gag
+3211 gains
+3212 gala
+3213 game
+3214 gap
+3215 gas
+3216 gave
+3221 gear
+3222 gecko
+3223 geek
+3224 gem
+3225 genre
+3226 gift
+3231 gig
+3232 gills
+3233 given
+3234 giver
+3235 glad
+3236 glass
+3241 glide
+3242 gloss
+3243 glove
+3244 glow
+3245 glue
+3246 goal
+3251 going
+3252 golf
+3253 gong
+3254 good
+3255 gooey
+3256 goofy
+3261 gore
+3262 gown
+3263 grab
+3264 grain
+3265 grant
+3266 grape
+3311 graph
+3312 grasp
+3313 grass
+3314 grave
+3315 gravy
+3316 gray
+3321 green
+3322 greet
+3323 grew
+3324 grid
+3325 grief
+3326 grill
+3331 grip
+3332 grit
+3333 groom
+3334 grope
+3335 growl
+3336 grub
+3341 grunt
+3342 guide
+3343 gulf
+3344 gulp
+3345 gummy
+3346 guru
+3351 gush
+3352 gut
+3353 guy
+3354 habit
+3355 half
+3356 halo
+3361 halt
+3362 happy
+3363 harm
+3364 hash
+3365 hasty
+3366 hatch
+3411 hate
+3412 haven
+3413 hazel
+3414 hazy
+3415 heap
+3416 heat
+3421 heave
+3422 hedge
+3423 hefty
+3424 help
+3425 herbs
+3426 hers
+3431 hub
+3432 hug
+3433 hula
+3434 hull
+3435 human
+3436 humid
+3441 hump
+3442 hung
+3443 hunk
+3444 hunt
+3445 hurry
+3446 hurt
+3451 hush
+3452 hut
+3453 ice
+3454 icing
+3455 icon
+3456 icy
+3461 igloo
+3462 image
+3463 ion
+3464 iron
+3465 islam
+3466 issue
+3511 item
+3512 ivory
+3513 ivy
+3514 jab
+3515 jam
+3516 jaws
+3521 jazz
+3522 jeep
+3523 jelly
+3524 jet
+3525 jiffy
+3526 job
+3531 jog
+3532 jolly
+3533 jolt
+3534 jot
+3535 joy
+3536 judge
+3541 juice
+3542 juicy
+3543 july
+3544 jumbo
+3545 jump
+3546 junky
+3551 juror
+3552 jury
+3553 keep
+3554 keg
+3555 kept
+3556 kick
+3561 kilt
+3562 king
+3563 kite
+3564 kitty
+3565 kiwi
+3566 knee
+3611 knelt
+3612 koala
+3613 kung
+3614 ladle
+3615 lady
+3616 lair
+3621 lake
+3622 lance
+3623 land
+3624 lapel
+3625 large
+3626 lash
+3631 lasso
+3632 last
+3633 latch
+3634 late
+3635 lazy
+3636 left
+3641 legal
+3642 lemon
+3643 lend
+3644 lens
+3645 lent
+3646 level
+3651 lever
+3652 lid
+3653 life
+3654 lift
+3655 lilac
+3656 lily
+3661 limb
+3662 limes
+3663 line
+3664 lint
+3665 lion
+3666 lip
+4111 list
+4112 lived
+4113 liver
+4114 lunar
+4115 lunch
+4116 lung
+4121 lurch
+4122 lure
+4123 lurk
+4124 lying
+4125 lyric
+4126 mace
+4131 maker
+4132 malt
+4133 mama
+4134 mango
+4135 manor
+4136 many
+4141 map
+4142 march
+4143 mardi
+4144 marry
+4145 mash
+4146 match
+4151 mate
+4152 math
+4153 moan
+4154 mocha
+4155 moist
+4156 mold
+4161 mom
+4162 moody
+4163 mop
+4164 morse
+4165 most
+4166 motor
+4211 motto
+4212 mount
+4213 mouse
+4214 mousy
+4215 mouth
+4216 move
+4221 movie
+4222 mower
+4223 mud
+4224 mug
+4225 mulch
+4226 mule
+4231 mull
+4232 mumbo
+4233 mummy
+4234 mural
+4235 muse
+4236 music
+4241 musky
+4242 mute
+4243 nacho
+4244 nag
+4245 nail
+4246 name
+4251 nanny
+4252 nap
+4253 navy
+4254 near
+4255 neat
+4256 neon
+4261 nerd
+4262 nest
+4263 net
+4264 next
+4265 niece
+4266 ninth
+4311 nutty
+4312 oak
+4313 oasis
+4314 oat
+4315 ocean
+4316 oil
+4321 old
+4322 olive
+4323 omen
+4324 onion
+4325 only
+4326 ooze
+4331 opal
+4332 open
+4333 opera
+4334 opt
+4335 otter
+4336 ouch
+4341 ounce
+4342 outer
+4343 oval
+4344 oven
+4345 owl
+4346 ozone
+4351 pace
+4352 pagan
+4353 pager
+4354 palm
+4355 panda
+4356 panic
+4361 pants
+4362 panty
+4363 paper
+4364 park
+4365 party
+4366 pasta
+4411 patch
+4412 path
+4413 patio
+4414 payer
+4415 pecan
+4416 penny
+4421 pep
+4422 perch
+4423 perky
+4424 perm
+4425 pest
+4426 petal
+4431 petri
+4432 petty
+4433 photo
+4434 plank
+4435 plant
+4436 plaza
+4441 plead
+4442 plot
+4443 plow
+4444 pluck
+4445 plug
+4446 plus
+4451 poach
+4452 pod
+4453 poem
+4454 poet
+4455 pogo
+4456 point
+4461 poise
+4462 poker
+4463 polar
+4464 polio
+4465 polka
+4466 polo
+4511 pond
+4512 pony
+4513 poppy
+4514 pork
+4515 poser
+4516 pouch
+4521 pound
+4522 pout
+4523 power
+4524 prank
+4525 press
+4526 print
+4531 prior
+4532 prism
+4533 prize
+4534 probe
+4535 prong
+4536 proof
+4541 props
+4542 prude
+4543 prune
+4544 pry
+4545 pug
+4546 pull
+4551 pulp
+4552 pulse
+4553 puma
+4554 punch
+4555 punk
+4556 pupil
+4561 puppy
+4562 purr
+4563 purse
+4564 push
+4565 putt
+4566 quack
+4611 quake
+4612 query
+4613 quiet
+4614 quill
+4615 quilt
+4616 quit
+4621 quota
+4622 quote
+4623 rabid
+4624 race
+4625 rack
+4626 radar
+4631 radio
+4632 raft
+4633 rage
+4634 raid
+4635 rail
+4636 rake
+4641 rally
+4642 ramp
+4643 ranch
+4644 range
+4645 rank
+4646 rant
+4651 rash
+4652 raven
+4653 reach
+4654 react
+4655 ream
+4656 rebel
+4661 recap
+4662 relax
+4663 relay
+4664 relic
+4665 remix
+4666 repay
+5111 repel
+5112 reply
+5113 rerun
+5114 reset
+5115 rhyme
+5116 rice
+5121 rich
+5122 ride
+5123 rigid
+5124 rigor
+5125 rinse
+5126 riot
+5131 ripen
+5132 rise
+5133 risk
+5134 ritzy
+5135 rival
+5136 river
+5141 roast
+5142 robe
+5143 robin
+5144 rock
+5145 rogue
+5146 roman
+5151 romp
+5152 rope
+5153 rover
+5154 royal
+5155 ruby
+5156 rug
+5161 ruin
+5162 rule
+5163 runny
+5164 rush
+5165 rust
+5166 rut
+5211 sadly
+5212 sage
+5213 said
+5214 saint
+5215 salad
+5216 salon
+5221 salsa
+5222 salt
+5223 same
+5224 sandy
+5225 santa
+5226 satin
+5231 sauna
+5232 saved
+5233 savor
+5234 sax
+5235 say
+5236 scale
+5241 scam
+5242 scan
+5243 scare
+5244 scarf
+5245 scary
+5246 scoff
+5251 scold
+5252 scoop
+5253 scoot
+5254 scope
+5255 score
+5256 scorn
+5261 scout
+5262 scowl
+5263 scrap
+5264 scrub
+5265 scuba
+5266 scuff
+5311 sect
+5312 sedan
+5313 self
+5314 send
+5315 sepia
+5316 serve
+5321 set
+5322 seven
+5323 shack
+5324 shade
+5325 shady
+5326 shaft
+5331 shaky
+5332 sham
+5333 shape
+5334 share
+5335 sharp
+5336 shed
+5341 sheep
+5342 sheet
+5343 shelf
+5344 shell
+5345 shine
+5346 shiny
+5351 ship
+5352 shirt
+5353 shock
+5354 shop
+5355 shore
+5356 shout
+5361 shove
+5362 shown
+5363 showy
+5364 shred
+5365 shrug
+5366 shun
+5411 shush
+5412 shut
+5413 shy
+5414 sift
+5415 silk
+5416 silly
+5421 silo
+5422 sip
+5423 siren
+5424 sixth
+5425 size
+5426 skate
+5431 skew
+5432 skid
+5433 skier
+5434 skies
+5435 skip
+5436 skirt
+5441 skit
+5442 sky
+5443 slab
+5444 slack
+5445 slain
+5446 slam
+5451 slang
+5452 slash
+5453 slate
+5454 slaw
+5455 sled
+5456 sleek
+5461 sleep
+5462 sleet
+5463 slept
+5464 slice
+5465 slick
+5466 slimy
+5511 sling
+5512 slip
+5513 slit
+5514 slob
+5515 slot
+5516 slug
+5521 slum
+5522 slurp
+5523 slush
+5524 small
+5525 smash
+5526 smell
+5531 smile
+5532 smirk
+5533 smog
+5534 snack
+5535 snap
+5536 snare
+5541 snarl
+5542 sneak
+5543 sneer
+5544 sniff
+5545 snore
+5546 snort
+5551 snout
+5552 snowy
+5553 snub
+5554 snuff
+5555 speak
+5556 speed
+5561 spend
+5562 spent
+5563 spew
+5564 spied
+5565 spill
+5566 spiny
+5611 spoil
+5612 spoke
+5613 spoof
+5614 spool
+5615 spoon
+5616 sport
+5621 spot
+5622 spout
+5623 spray
+5624 spree
+5625 spur
+5626 squad
+5631 squat
+5632 squid
+5633 stack
+5634 staff
+5635 stage
+5636 stain
+5641 stall
+5642 stamp
+5643 stand
+5644 stank
+5645 stark
+5646 start
+5651 stash
+5652 state
+5653 stays
+5654 steam
+5655 steep
+5656 stem
+5661 step
+5662 stew
+5663 stick
+5664 sting
+5665 stir
+5666 stock
+6111 stole
+6112 stomp
+6113 stony
+6114 stood
+6115 stool
+6116 stoop
+6121 stop
+6122 storm
+6123 stout
+6124 stove
+6125 straw
+6126 stray
+6131 strut
+6132 stuck
+6133 stud
+6134 stuff
+6135 stump
+6136 stung
+6141 stunt
+6142 suds
+6143 sugar
+6144 sulk
+6145 surf
+6146 sushi
+6151 swab
+6152 swan
+6153 swarm
+6154 sway
+6155 swear
+6156 sweat
+6161 sweep
+6162 swell
+6163 swept
+6164 swim
+6165 swing
+6166 swipe
+6211 swirl
+6212 swoop
+6213 swore
+6214 syrup
+6215 tacky
+6216 taco
+6221 tag
+6222 take
+6223 tall
+6224 talon
+6225 tamer
+6226 tank
+6231 taper
+6232 taps
+6233 tarot
+6234 tart
+6235 task
+6236 taste
+6241 tasty
+6242 taunt
+6243 thank
+6244 thaw
+6245 theft
+6246 theme
+6251 thigh
+6252 thing
+6253 think
+6254 thong
+6255 thorn
+6256 those
+6261 throb
+6262 thud
+6263 thumb
+6264 thump
+6265 thus
+6266 tiara
+6311 tidal
+6312 tidy
+6313 tiger
+6314 tile
+6315 tilt
+6316 tint
+6321 tiny
+6322 trace
+6323 track
+6324 trade
+6325 train
+6326 trait
+6331 trap
+6332 trash
+6333 tray
+6334 treat
+6335 tree
+6336 trek
+6341 trend
+6342 trial
+6343 tribe
+6344 trick
+6345 trio
+6346 trout
+6351 truce
+6352 truck
+6353 trump
+6354 trunk
+6355 try
+6356 tug
+6361 tulip
+6362 tummy
+6363 turf
+6364 tusk
+6365 tutor
+6366 tutu
+6411 tux
+6412 tweak
+6413 tweet
+6414 twice
+6415 twine
+6416 twins
+6421 twirl
+6422 twist
+6423 uncle
+6424 uncut
+6425 undo
+6426 unify
+6431 union
+6432 unit
+6433 untie
+6434 upon
+6435 upper
+6436 urban
+6441 used
+6442 user
+6443 usher
+6444 utter
+6445 value
+6446 vapor
+6451 vegan
+6452 venue
+6453 verse
+6454 vest
+6455 veto
+6456 vice
+6461 video
+6462 view
+6463 viral
+6464 virus
+6465 visa
+6466 visor
+6511 vixen
+6512 vocal
+6513 voice
+6514 void
+6515 volt
+6516 voter
+6521 vowel
+6522 wad
+6523 wafer
+6524 wager
+6525 wages
+6526 wagon
+6531 wake
+6532 walk
+6533 wand
+6534 wasp
+6535 watch
+6536 water
+6541 wavy
+6542 wheat
+6543 whiff
+6544 whole
+6545 whoop
+6546 wick
+6551 widen
+6552 widow
+6553 width
+6554 wife
+6555 wifi
+6556 wilt
+6561 wimp
+6562 wind
+6563 wing
+6564 wink
+6565 wipe
+6566 wired
+6611 wiry
+6612 wise
+6613 wish
+6614 wispy
+6615 wok
+6616 wolf
+6621 womb
+6622 wool
+6623 woozy
+6624 word
+6625 work
+6626 worry
+6631 wound
+6632 woven
+6633 wrath
+6634 wreck
+6635 wrist
+6636 xerox
+6641 yahoo
+6642 yam
+6643 yard
+6644 year
+6645 yeast
+6646 yelp
+6651 yield
+6652 yo-yo
+6653 yodel
+6654 yoga
+6655 yoyo
+6656 yummy
+6661 zebra
+6662 zero
+6663 zesty
+6664 zippy
+6665 zone
+6666 zoom
diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp
index 0baa8ddec..8c7d0967d 100644
--- a/src/engine/server/server.cpp
+++ b/src/engine/server/server.cpp
@@ -2828,12 +2828,18 @@ void CServer::ConAddSqlServer(IConsole::IResult *pResult, void *pUserData)
{
apSqlServers[i] = new CSqlServer(pResult->GetString(1), pResult->GetString(2), pResult->GetString(3), pResult->GetString(4), pResult->GetString(5), pResult->GetInteger(6), &pSelf->m_GlobalSqlLock, ReadOnly, SetUpDb);
- if(SetUpDb)
- thread_init(CreateTablesThread, apSqlServers[i], "CreateTables");
-
char aBuf[512];
- str_format(aBuf, sizeof(aBuf), "Added new Sql%sServer: %d: DB: '%s' Prefix: '%s' User: '%s' IP: <{'%s'}> Port: %d", ReadOnly ? "Read" : "Write", i, apSqlServers[i]->GetDatabase(), apSqlServers[i]->GetPrefix(), apSqlServers[i]->GetUser(), apSqlServers[i]->GetIP(), apSqlServers[i]->GetPort());
+ str_format(aBuf, sizeof(aBuf),
+ "Added new Sql%sServer: %d: DB: '%s' Prefix: '%s' User: '%s' IP: <{'%s'}> Port: %d",
+ ReadOnly ? "Read" : "Write", i, apSqlServers[i]->GetDatabase(),
+ apSqlServers[i]->GetPrefix(), apSqlServers[i]->GetUser(),
+ apSqlServers[i]->GetIP(), apSqlServers[i]->GetPort());
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
+ if(SetUpDb)
+ {
+ if(!apSqlServers[i]->CreateTables())
+ pSelf->SetErrorShutdown("database create tables failed");
+ }
return;
}
}
@@ -2866,11 +2872,6 @@ void CServer::ConDumpSqlServers(IConsole::IResult *pResult, void *pUserData)
}
}
-void CServer::CreateTablesThread(void *pData)
-{
- ((CSqlServer *)pData)->CreateTables();
-}
-
#endif
void CServer::ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
diff --git a/src/engine/server/server.h b/src/engine/server/server.h
index 6c8a456cb..1889434d0 100644
--- a/src/engine/server/server.h
+++ b/src/engine/server/server.h
@@ -377,8 +377,6 @@ public:
// console commands for sqlmasters
static void ConAddSqlServer(IConsole::IResult *pResult, void *pUserData);
static void ConDumpSqlServers(IConsole::IResult *pResult, void *pUserData);
-
- static void CreateTablesThread(void *pData);
#endif
static void ConchainSpecialInfoupdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
diff --git a/src/engine/server/sql_server.cpp b/src/engine/server/sql_server.cpp
index 32304dbaf..58f7bddb8 100644
--- a/src/engine/server/sql_server.cpp
+++ b/src/engine/server/sql_server.cpp
@@ -167,11 +167,12 @@ void CSqlServer::Disconnect()
m_SqlLock.release();
}
-void CSqlServer::CreateTables()
+bool CSqlServer::CreateTables()
{
if (!Connect())
- return;
+ return false;
+ bool Success = false;
try
{
char aBuf[1024];
@@ -186,13 +187,14 @@ void CSqlServer::CreateTables()
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_maps (Map VARCHAR(128) BINARY NOT NULL, Server VARCHAR(32) BINARY NOT NULL, Mapper VARCHAR(128) BINARY NOT NULL, Points INT DEFAULT 0, Stars INT DEFAULT 0, Timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY Map (Map)) CHARACTER SET utf8mb4;", m_aPrefix);
executeSql(aBuf);
- str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_saves (Savegame TEXT CHARACTER SET utf8mb4 BINARY NOT NULL, Map VARCHAR(128) BINARY NOT NULL, Code VARCHAR(128) BINARY NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, Server CHAR(4), DDNet7 BOOL DEFAULT FALSE, UNIQUE KEY (Map, Code)) CHARACTER SET utf8mb4;", m_aPrefix);
+ str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_saves (Savegame TEXT CHARACTER SET utf8mb4 BINARY NOT NULL, Map VARCHAR(128) BINARY NOT NULL, Code VARCHAR(128) BINARY NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, Server CHAR(4), DDNet7 BOOL DEFAULT FALSE, SaveID VARCHAR(36), UNIQUE KEY (Map, Code)) CHARACTER SET utf8mb4;", m_aPrefix);
executeSql(aBuf);
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_points (Name VARCHAR(%d) BINARY NOT NULL, Points INT DEFAULT 0, UNIQUE KEY Name (Name)) CHARACTER SET utf8mb4;", m_aPrefix, MAX_NAME_LENGTH);
executeSql(aBuf);
dbg_msg("sql", "Tables were created successfully");
+ Success = true;
}
catch (sql::SQLException &e)
{
@@ -200,6 +202,7 @@ void CSqlServer::CreateTables()
}
Disconnect();
+ return Success;
}
void CSqlServer::executeSql(const char *pCommand)
diff --git a/src/engine/server/sql_server.h b/src/engine/server/sql_server.h
index ee85d5ace..3b6a39a8e 100644
--- a/src/engine/server/sql_server.h
+++ b/src/engine/server/sql_server.h
@@ -17,7 +17,7 @@ public:
bool Connect();
void Disconnect();
- void CreateTables();
+ bool CreateTables();
void executeSql(const char *pCommand);
void executeSqlQuery(const char *pQuery);
@@ -30,6 +30,7 @@ public:
const char* GetPass() { return m_aPass; }
const char* GetIP() { return m_aIp; }
int GetPort() { return m_Port; }
+ sql::Connection *Connection() const { return m_pConnection; }
static int ms_NumReadServer;
static int ms_NumWriteServer;
diff --git a/src/engine/server/sql_string_helpers.h b/src/engine/server/sql_string_helpers.h
index bb9ae80bb..342be3f98 100644
--- a/src/engine/server/sql_string_helpers.h
+++ b/src/engine/server/sql_string_helpers.h
@@ -1,6 +1,8 @@
#ifndef ENGINE_SERVER_SQL_STRING_HELPERS_H
#define ENGINE_SERVER_SQL_STRING_HELPERS_H
+#include
+
namespace sqlstr
{
@@ -30,7 +32,7 @@ public:
const char* Str() const { return m_aString; }
const char* ClrStr() const { return m_aClearString; }
- CSqlString& operator = (const char *pStr)
+ CSqlString& operator=(const char *pStr)
{
str_copy(m_aString, pStr, size);
str_copy(m_aClearString, pStr, size);
@@ -38,6 +40,11 @@ public:
return *this;
}
+ bool operator<(const CSqlString& other) const
+ {
+ return strcmp(m_aString, other.m_aString) < 0;
+ }
+
private:
char m_aString[size];
char m_aClearString[size * 2 - 1];
diff --git a/src/game/server/ddracechat.cpp b/src/game/server/ddracechat.cpp
index 7be20d337..4f4035fa3 100644
--- a/src/game/server/ddracechat.cpp
+++ b/src/game/server/ddracechat.cpp
@@ -386,10 +386,9 @@ void CGameContext::ConTeamTop5(IConsole::IResult *pResult, void *pUserData)
}
if (pResult->NumArguments() > 0)
- pSelf->Score()->ShowTeamTop5(pResult, pResult->m_ClientID, pUserData,
- pResult->GetInteger(0));
+ pSelf->Score()->ShowTeamTop5(pResult->m_ClientID, pResult->GetInteger(0));
else
- pSelf->Score()->ShowTeamTop5(pResult, pResult->m_ClientID, pUserData);
+ pSelf->Score()->ShowTeamTop5(pResult->m_ClientID);
#if defined(CONF_SQL)
if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL)
@@ -417,10 +416,9 @@ void CGameContext::ConTop5(IConsole::IResult *pResult, void *pUserData)
}
if (pResult->NumArguments() > 0)
- pSelf->Score()->ShowTop5(pResult, pResult->m_ClientID, pUserData,
- pResult->GetInteger(0));
+ pSelf->Score()->ShowTop5(pResult->m_ClientID, pResult->GetInteger(0));
else
- pSelf->Score()->ShowTop5(pResult, pResult->m_ClientID, pUserData);
+ pSelf->Score()->ShowTop5(pResult->m_ClientID);
#if defined(CONF_SQL)
if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL)
@@ -520,13 +518,16 @@ void CGameContext::ConMap(IConsole::IResult *pResult, void *pUserData)
if (!pPlayer)
return;
+ if(pSelf->RateLimitPlayerVote(pResult->m_ClientID) || pSelf->RateLimitPlayerMapVote(pResult->m_ClientID))
+ return;
+
#if defined(CONF_SQL)
if(g_Config.m_SvUseSQL)
if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick())
return;
#endif
- pSelf->Score()->MapVote(&pSelf->m_pMapVoteResult, pResult->m_ClientID, pResult->GetString(0));
+ pSelf->Score()->MapVote(pResult->m_ClientID, pResult->GetString(0));
#if defined(CONF_SQL)
if(g_Config.m_SvUseSQL)
@@ -695,19 +696,20 @@ void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData)
if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick())
return;
- int Team = ((CGameControllerDDRace*) pSelf->m_pController)->m_Teams.m_Core.Team(pResult->m_ClientID);
+ const char* pCode = "";
+ if(pResult->NumArguments() > 0)
+ pCode = pResult->GetString(0);
- const char* pCode = pResult->GetString(0);
char aCountry[5];
- if(str_length(pCode) > 3 && pCode[0] >= 'A' && pCode[0] <= 'Z' && pCode[1] >= 'A'
+ if(str_length(pCode) >= 3 && pCode[0] >= 'A' && pCode[0] <= 'Z' && pCode[1] >= 'A'
&& pCode[1] <= 'Z' && pCode[2] >= 'A' && pCode[2] <= 'Z')
{
- if(pCode[3] == ' ')
+ if(str_length(pCode) == 3 || pCode[3] == ' ')
{
str_copy(aCountry, pCode, 4);
pCode = str_skip_whitespaces_const(pCode + 4);
}
- else if(str_length(pCode) > 4 && pCode[4] == ' ')
+ else if(str_length(pCode) == 4 || (str_length(pCode) > 4 && pCode[4] == ' '))
{
str_copy(aCountry, pCode, 5);
pCode = str_skip_whitespaces_const(pCode + 5);
@@ -724,7 +726,7 @@ void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData)
if(str_in_list(g_Config.m_SvSqlValidServerNames, ",", aCountry))
{
- pSelf->Score()->SaveTeam(Team, pCode, pResult->m_ClientID, aCountry);
+ pSelf->Score()->SaveTeam(pResult->m_ClientID, pCode, aCountry);
if(g_Config.m_SvUseSQL)
pPlayer->m_LastSQLQuery = pSelf->Server()->Tick();
@@ -790,8 +792,7 @@ void CGameContext::ConTeamRank(IConsole::IResult *pResult, void *pUserData)
if (pResult->NumArguments() > 0)
if (!g_Config.m_SvHideScore)
- pSelf->Score()->ShowTeamRank(pResult->m_ClientID, pResult->GetString(0),
- true);
+ pSelf->Score()->ShowTeamRank(pResult->m_ClientID, pResult->GetString(0));
else
pSelf->Console()->Print(
IConsole::OUTPUT_LEVEL_STANDARD,
@@ -825,8 +826,7 @@ void CGameContext::ConRank(IConsole::IResult *pResult, void *pUserData)
if (pResult->NumArguments() > 0)
if (!g_Config.m_SvHideScore)
- pSelf->Score()->ShowRank(pResult->m_ClientID, pResult->GetString(0),
- true);
+ pSelf->Score()->ShowRank(pResult->m_ClientID, pResult->GetString(0));
else
pSelf->Console()->Print(
IConsole::OUTPUT_LEVEL_STANDARD,
@@ -1548,8 +1548,7 @@ void CGameContext::ConPoints(IConsole::IResult *pResult, void *pUserData)
if (pResult->NumArguments() > 0)
if (!g_Config.m_SvHideScore)
- pSelf->Score()->ShowPoints(pResult->m_ClientID, pResult->GetString(0),
- true);
+ pSelf->Score()->ShowPoints(pResult->m_ClientID, pResult->GetString(0));
else
pSelf->Console()->Print(
IConsole::OUTPUT_LEVEL_STANDARD,
@@ -1583,10 +1582,9 @@ void CGameContext::ConTopPoints(IConsole::IResult *pResult, void *pUserData)
}
if (pResult->NumArguments() > 0)
- pSelf->Score()->ShowTopPoints(pResult, pResult->m_ClientID, pUserData,
- pResult->GetInteger(0));
+ pSelf->Score()->ShowTopPoints(pResult->m_ClientID, pResult->GetInteger(0));
else
- pSelf->Score()->ShowTopPoints(pResult, pResult->m_ClientID, pUserData);
+ pSelf->Score()->ShowTopPoints(pResult->m_ClientID);
if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL)
pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery = pSelf->Server()->Tick();
diff --git a/src/game/server/ddracechat.h b/src/game/server/ddracechat.h
index e0d3ec894..48787a00c 100644
--- a/src/game/server/ddracechat.h
+++ b/src/game/server/ddracechat.h
@@ -27,7 +27,7 @@ CHAT_COMMAND("dnd", "", CFGFLAG_CHAT|CFGFLAG_SERVER|CFGFLAG_NONTEEHISTORIC, ConD
CHAT_COMMAND("mapinfo", "?r[map]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConMapInfo, this, "Show info about the map with name r gives (current map by default)")
CHAT_COMMAND("timeout", "?s[code]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTimeout, this, "Set timeout protection code s")
CHAT_COMMAND("practice", "?i['0'|'1']", CFGFLAG_CHAT|CFGFLAG_SERVER, ConPractice, this, "Enable cheats (currently only /rescue) for your current team's run, but you can't earn a rank")
-CHAT_COMMAND("save", "r[code]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConSave, this, "Save team with code r to current server. To save to another server, use '/save s r' where s = server (case-sensitive: GER, RUS, etc) and r = code.")
+CHAT_COMMAND("save", "?r[code]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConSave, this, "Save team with code r to current server. To save to another server, use '/save s r' where s = server (case-sensitive: GER, RUS, etc) and r = code.")
CHAT_COMMAND("load", "?r[code]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConLoad, this, "Load with code r. /load to check your existing saves")
CHAT_COMMAND("map", "?r[map]", CFGFLAG_CHAT|CFGFLAG_SERVER|CFGFLAG_NONTEEHISTORIC, ConMap, this, "Vote a map by name")
CHAT_COMMAND("rankteam", "?r[player name]", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTeamRank, this, "Shows the team rank of player with name r (your team rank by default)")
diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp
index 8e7ed6273..a523bb562 100644
--- a/src/game/server/entities/character.cpp
+++ b/src/game/server/entities/character.cpp
@@ -1503,6 +1503,26 @@ void CCharacter::HandleTiles(int Index)
// start
if(((m_TileIndex == TILE_BEGIN) || (m_TileFIndex == TILE_BEGIN) || FTile1 == TILE_BEGIN || FTile2 == TILE_BEGIN || FTile3 == TILE_BEGIN || FTile4 == TILE_BEGIN || Tile1 == TILE_BEGIN || Tile2 == TILE_BEGIN || Tile3 == TILE_BEGIN || Tile4 == TILE_BEGIN) && (m_DDRaceState == DDRACE_NONE || m_DDRaceState == DDRACE_FINISHED || (m_DDRaceState == DDRACE_STARTED && !Team() && g_Config.m_SvTeam != 3)))
{
+ if(Teams()->GetSaving(Team()))
+ {
+ if(m_LastStartWarning < Server()->Tick() - 3 * Server()->TickSpeed())
+ {
+ GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You can't start while loading/saving of team is in progress");
+ m_LastStartWarning = Server()->Tick();
+ }
+ Die(GetPlayer()->GetCID(), WEAPON_WORLD);
+ return;
+ }
+ if(g_Config.m_SvTeam == 2 && (Team() == TEAM_FLOCK || Teams()->Count(Team()) <= 1))
+ {
+ if(m_LastStartWarning < Server()->Tick() - 3 * Server()->TickSpeed())
+ {
+ GameServer()->SendChatTarget(GetPlayer()->GetCID(), "You have to be in a team with other tees to start");
+ m_LastStartWarning = Server()->Tick();
+ }
+ Die(GetPlayer()->GetCID(), WEAPON_WORLD);
+ return;
+ }
if(g_Config.m_SvResetPickups)
{
for (int i = WEAPON_SHOTGUN; i < NUM_WEAPONS; ++i)
@@ -1512,16 +1532,6 @@ void CCharacter::HandleTiles(int Index)
m_Core.m_ActiveWeapon = WEAPON_GUN;
}
}
- if(g_Config.m_SvTeam == 2 && (Team() == TEAM_FLOCK || Teams()->Count(Team()) <= 1))
- {
- if(m_LastStartWarning < Server()->Tick() - 3 * Server()->TickSpeed())
- {
- GameServer()->SendChatTarget(GetPlayer()->GetCID(),"You have to be in a team with other tees to start");
- m_LastStartWarning = Server()->Tick();
- }
- Die(GetPlayer()->GetCID(), WEAPON_WORLD);
- return;
- }
Teams()->OnCharacterStart(m_pPlayer->GetCID());
m_CpActive = -2;
diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp
index f78447fee..56369415c 100644
--- a/src/game/server/gamecontext.cpp
+++ b/src/game/server/gamecontext.cpp
@@ -57,9 +57,6 @@ void CGameContext::Construct(int Resetting)
m_ChatResponseTargetID = -1;
m_aDeleteTempfile[0] = 0;
m_TeeHistorianActive = false;
-
- m_pRandomMapResult = nullptr;
- m_pMapVoteResult = nullptr;
}
CGameContext::CGameContext(int Resetting)
@@ -901,6 +898,7 @@ void CGameContext::OnTick()
}
if(Collision()->m_NumSwitchers > 0)
+ {
for (int i = 0; i < Collision()->m_NumSwitchers+1; ++i)
{
for (int j = 0; j < MAX_CLIENTS; ++j)
@@ -919,28 +917,6 @@ void CGameContext::OnTick()
}
}
}
-
- if(m_pRandomMapResult && m_pRandomMapResult->m_Done)
- {
- str_copy(g_Config.m_SvMap, m_pRandomMapResult->m_aMap, sizeof(g_Config.m_SvMap));
- m_pRandomMapResult = NULL;
- }
-
- if(m_pMapVoteResult && m_pMapVoteResult->m_Done)
- {
- m_VoteKick = false;
- m_VoteSpec = false;
- m_LastMapVote = time_get();
-
- char aCmd[256];
- str_format(aCmd, sizeof(aCmd), "sv_reset_file types/%s/flexreset.cfg; change_map \"%s\"", m_pMapVoteResult->m_aServer, m_pMapVoteResult->m_aMap);
-
- char aChatmsg[512];
- str_format(aChatmsg, sizeof(aChatmsg), "'%s' called vote to change server option '%s' (%s)", Server()->ClientName(m_pMapVoteResult->m_ClientID), m_pMapVoteResult->m_aMap, "/map");
-
- CallVote(m_pMapVoteResult->m_ClientID, m_pMapVoteResult->m_aMap, aCmd, "/map", aChatmsg);
-
- m_pMapVoteResult = NULL;
}
#ifdef CONF_DEBUG
@@ -1076,8 +1052,7 @@ void CGameContext::OnClientEnter(int ClientID)
// Can't set score here as LoadScore() is threaded, run it in
// LoadScoreThreaded() instead
- Score()->LoadScore(ClientID);
- Score()->CheckBirthday(ClientID);
+ Score()->LoadPlayerData(ClientID);
{
int Empty = -1;
@@ -1424,68 +1399,8 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
}
else if(MsgID == NETMSGTYPE_CL_CALLVOTE)
{
- int64 Now = Server()->Tick();
- int64 TickSpeed = Server()->TickSpeed();
-
- if(g_Config.m_SvRconVote && !Server()->GetAuthedState(ClientID))
- {
- SendChatTarget(ClientID, "You can only vote after logging in.");
+ if(RateLimitPlayerVote(ClientID))
return;
- }
-
- if (g_Config.m_SvDnsblVote && !m_pServer->DnsblWhite(ClientID) && Server()->DistinctClientCount() > 1)
- {
- // blacklisted by dnsbl
- SendChatTarget(ClientID, "You are not allowed to vote due to DNSBL.");
- return;
- }
-
- if(g_Config.m_SvSpamprotection && pPlayer->m_LastVoteTry && pPlayer->m_LastVoteTry + TickSpeed * 3 > Now)
- return;
-
- pPlayer->m_LastVoteTry = Now;
- if(g_Config.m_SvSpectatorVotes == 0 && pPlayer->GetTeam() == TEAM_SPECTATORS)
- {
- SendChatTarget(ClientID, "Spectators aren't allowed to start a vote.");
- return;
- }
-
- if(m_VoteCloseTime)
- {
- SendChatTarget(ClientID, "Wait for current vote to end before calling a new one.");
- return;
- }
-
- if(Now < pPlayer->m_FirstVoteTick)
- {
- char aBuf[64];
- str_format(aBuf, sizeof(aBuf), "You must wait %d seconds before making your first vote.", (int)((pPlayer->m_FirstVoteTick - Now) / TickSpeed) + 1);
- SendChatTarget(ClientID, aBuf);
- return;
- }
-
- int TimeLeft = pPlayer->m_LastVoteCall + TickSpeed * g_Config.m_SvVoteDelay - Now;
- if(pPlayer->m_LastVoteCall && TimeLeft > 0)
- {
- char aChatmsg[64];
- str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote.", (int)(TimeLeft / TickSpeed) + 1);
- SendChatTarget(ClientID, aChatmsg);
- return;
- }
-
- NETADDR Addr;
- Server()->GetClientAddr(ClientID, &Addr);
- int VoteMuted = 0;
- for(int i = 0; i < m_NumVoteMutes && !VoteMuted; i++)
- if(!net_addr_comp_noport(&Addr, &m_aVoteMutes[i].m_Addr))
- VoteMuted = (m_aVoteMutes[i].m_Expire - Server()->Tick()) / Server()->TickSpeed();
- if(VoteMuted > 0)
- {
- char aChatmsg[64];
- str_format(aChatmsg, sizeof(aChatmsg), "You are not permitted to vote for the next %d seconds.", VoteMuted);
- SendChatTarget(ClientID, aChatmsg);
- return;
- }
char aChatmsg[512] = {0};
char aDesc[VOTE_DESC_LENGTH] = {0};
@@ -1516,11 +1431,12 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
SendChatTarget(ClientID, "Invalid option");
return;
}
- if(!Authed && (str_startswith(pOption->m_aCommand, "sv_map ") || str_startswith(pOption->m_aCommand, "change_map ") || str_startswith(pOption->m_aCommand, "random_map") || str_startswith(pOption->m_aCommand, "random_unfinished_map")) && time_get() < m_LastMapVote + (time_freq() * g_Config.m_SvVoteMapTimeDelay))
+ if((str_startswith(pOption->m_aCommand, "sv_map ")
+ || str_startswith(pOption->m_aCommand, "change_map ")
+ || str_startswith(pOption->m_aCommand, "random_map")
+ || str_startswith(pOption->m_aCommand, "random_unfinished_map"))
+ && RateLimitPlayerMapVote(ClientID))
{
- str_format(aChatmsg, sizeof(aChatmsg), "There's a %d second delay between map-votes, please wait %d seconds.", g_Config.m_SvVoteMapTimeDelay, (int)(((m_LastMapVote+(g_Config.m_SvVoteMapTimeDelay * time_freq()))/time_freq())-(time_get()/time_freq())));
- SendChatTarget(ClientID, aChatmsg);
-
return;
}
@@ -1877,18 +1793,8 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
// reload scores
Score()->PlayerData(ClientID)->Reset();
- Score()->LoadScore(ClientID);
- Score()->PlayerData(ClientID)->m_CurrentTime = Score()->PlayerData(ClientID)->m_BestTime;
-
- // -9999 stands for no time and isn't displayed in scoreboard, so
- // shift the time by a second if the player actually took 9999
- // seconds to finish the map.
- if(!Score()->PlayerData(ClientID)->m_BestTime)
- m_apPlayers[ClientID]->m_Score = -9999;
- else if((int)Score()->PlayerData(ClientID)->m_BestTime == -9999)
- m_apPlayers[ClientID]->m_Score = -10000;
- else
- m_apPlayers[ClientID]->m_Score = Score()->PlayerData(ClientID)->m_BestTime;
+ m_apPlayers[ClientID]->m_Score = -9999;
+ Score()->LoadPlayerData(ClientID);
}
Server()->SetClientClan(ClientID, pMsg->m_pClan);
Server()->SetClientCountry(ClientID, pMsg->m_Country);
@@ -2241,7 +2147,7 @@ void CGameContext::ConRandomMap(IConsole::IResult *pResult, void *pUserData)
int Stars = pResult->NumArguments() ? pResult->GetInteger(0) : -1;
- pSelf->m_pScore->RandomMap(&pSelf->m_pRandomMapResult, pSelf->m_VoteCreator, Stars);
+ pSelf->m_pScore->RandomMap(pSelf->m_VoteCreator, Stars);
}
void CGameContext::ConRandomUnfinishedMap(IConsole::IResult *pResult, void *pUserData)
@@ -2250,7 +2156,7 @@ void CGameContext::ConRandomUnfinishedMap(IConsole::IResult *pResult, void *pUse
int Stars = pResult->NumArguments() ? pResult->GetInteger(0) : -1;
- pSelf->m_pScore->RandomUnfinishedMap(&pSelf->m_pRandomMapResult, pSelf->m_VoteCreator, Stars);
+ pSelf->m_pScore->RandomUnfinishedMap(pSelf->m_VoteCreator, Stars);
}
void CGameContext::ConRestart(IConsole::IResult *pResult, void *pUserData)
@@ -3591,3 +3497,84 @@ void CGameContext::ForceVote(int EnforcerID, bool Success)
str_format(aBuf, sizeof(aBuf), "forcing vote %s", pOption);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "server", aBuf);
}
+
+bool CGameContext::RateLimitPlayerVote(int ClientID)
+{
+ int64 Now = Server()->Tick();
+ int64 TickSpeed = Server()->TickSpeed();
+ CPlayer *pPlayer = m_apPlayers[ClientID];
+
+ if(g_Config.m_SvRconVote && !Server()->GetAuthedState(ClientID))
+ {
+ SendChatTarget(ClientID, "You can only vote after logging in.");
+ return true;
+ }
+
+ if (g_Config.m_SvDnsblVote && !m_pServer->DnsblWhite(ClientID) && Server()->DistinctClientCount() > 1)
+ {
+ // blacklisted by dnsbl
+ SendChatTarget(ClientID, "You are not allowed to vote due to DNSBL.");
+ return true;
+ }
+
+ if(g_Config.m_SvSpamprotection && pPlayer->m_LastVoteTry && pPlayer->m_LastVoteTry + TickSpeed * 3 > Now)
+ return true;
+
+ pPlayer->m_LastVoteTry = Now;
+ if(g_Config.m_SvSpectatorVotes == 0 && pPlayer->GetTeam() == TEAM_SPECTATORS)
+ {
+ SendChatTarget(ClientID, "Spectators aren't allowed to start a vote.");
+ return true;
+ }
+
+ if(m_VoteCloseTime)
+ {
+ SendChatTarget(ClientID, "Wait for current vote to end before calling a new one.");
+ return true;
+ }
+
+ if(Now < pPlayer->m_FirstVoteTick)
+ {
+ char aBuf[64];
+ str_format(aBuf, sizeof(aBuf), "You must wait %d seconds before making your first vote.", (int)((pPlayer->m_FirstVoteTick - Now) / TickSpeed) + 1);
+ SendChatTarget(ClientID, aBuf);
+ return true;
+ }
+
+ int TimeLeft = pPlayer->m_LastVoteCall + TickSpeed * g_Config.m_SvVoteDelay - Now;
+ if(pPlayer->m_LastVoteCall && TimeLeft > 0)
+ {
+ char aChatmsg[64];
+ str_format(aChatmsg, sizeof(aChatmsg), "You must wait %d seconds before making another vote.", (int)(TimeLeft / TickSpeed) + 1);
+ SendChatTarget(ClientID, aChatmsg);
+ return true;
+ }
+
+ NETADDR Addr;
+ Server()->GetClientAddr(ClientID, &Addr);
+ int VoteMuted = 0;
+ for(int i = 0; i < m_NumVoteMutes && !VoteMuted; i++)
+ if(!net_addr_comp_noport(&Addr, &m_aVoteMutes[i].m_Addr))
+ VoteMuted = (m_aVoteMutes[i].m_Expire - Server()->Tick()) / Server()->TickSpeed();
+ if(VoteMuted > 0)
+ {
+ char aChatmsg[64];
+ str_format(aChatmsg, sizeof(aChatmsg), "You are not permitted to vote for the next %d seconds.", VoteMuted);
+ SendChatTarget(ClientID, aChatmsg);
+ return true;
+ }
+ return false;
+}
+
+bool CGameContext::RateLimitPlayerMapVote(int ClientID)
+{
+ if(!Server()->GetAuthedState(ClientID) && time_get() < m_LastMapVote + (time_freq() * g_Config.m_SvVoteMapTimeDelay))
+ {
+ char aChatmsg[512] = {0};
+ str_format(aChatmsg, sizeof(aChatmsg), "There's a %d second delay between map-votes, please wait %d seconds.",
+ g_Config.m_SvVoteMapTimeDelay, (int)((m_LastMapVote + g_Config.m_SvVoteMapTimeDelay * time_freq() - time_get())/time_freq()));
+ SendChatTarget(ClientID, aChatmsg);
+ return true;
+ }
+ return false;
+}
diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h
index 061344005..6efb400de 100644
--- a/src/game/server/gamecontext.h
+++ b/src/game/server/gamecontext.h
@@ -57,8 +57,6 @@ enum
class IConsole;
class IEngine;
class IStorage;
-class CRandomMapResult;
-class CMapVoteResult;
struct CAntibotData;
class CGameContext : public IGameServer
@@ -81,9 +79,6 @@ class CGameContext : public IGameServer
CMapBugs m_MapBugs;
CPrng m_Prng;
- std::shared_ptr m_pRandomMapResult;
- std::shared_ptr m_pMapVoteResult;
-
static void CommandCallback(int ClientID, int FlagMask, const char *pCmd, IConsole::IResult *pResult, void *pUser);
static void TeeHistorianWrite(const void *pData, int DataSize, void *pUser);
@@ -264,6 +259,10 @@ public:
bool PlayerModerating();
void ForceVote(int EnforcerID, bool Success);
+ // Checks if player can vote and notify them about the reason
+ bool RateLimitPlayerVote(int ClientID);
+ bool RateLimitPlayerMapVote(int ClientID);
+
private:
bool m_VoteWillPass;
diff --git a/src/game/server/gamemodes/DDRace.cpp b/src/game/server/gamemodes/DDRace.cpp
index f0476e752..dd9c76c99 100644
--- a/src/game/server/gamemodes/DDRace.cpp
+++ b/src/game/server/gamemodes/DDRace.cpp
@@ -9,8 +9,12 @@
#include "DDRace.h"
#include "gamemode.h"
+#if defined(CONF_SQL)
+#include
+#endif
+
CGameControllerDDRace::CGameControllerDDRace(class CGameContext *pGameServer) :
- IGameController(pGameServer), m_Teams(pGameServer)
+ IGameController(pGameServer), m_Teams(pGameServer), m_pInitResult(nullptr)
{
m_pGameType = g_Config.m_SvTestingCommands ? TEST_NAME : GAME_NAME;
@@ -25,6 +29,18 @@ CGameControllerDDRace::~CGameControllerDDRace()
void CGameControllerDDRace::Tick()
{
IGameController::Tick();
+#if defined(CONF_SQL)
+ m_Teams.ProcessSaveTeam();
+
+ if(m_pInitResult != nullptr && m_pInitResult.use_count() == 1)
+ {
+ if(m_pInitResult->m_Done)
+ {
+ m_CurrentRecord = m_pInitResult->m_CurrentRecord;
+ }
+ m_pInitResult = nullptr;
+ }
+#endif
}
void CGameControllerDDRace::InitTeleporter()
diff --git a/src/game/server/gamemodes/DDRace.h b/src/game/server/gamemodes/DDRace.h
index 20be25cb5..0db166138 100644
--- a/src/game/server/gamemodes/DDRace.h
+++ b/src/game/server/gamemodes/DDRace.h
@@ -8,6 +8,7 @@
#include
#include