visual-driver
224 строки · 9.9 Кб
1@file:Suppress("UNCHECKED_CAST")
2
3import data.FeatureUserStorage
4import data.GraffitiPackStorage
5import data.GraffitiUnitStorage
6import kotlinx.coroutines.*
7import kotlinx.coroutines.future.await
8import me.func.protocol.graffiti.packet.GraffitiBuyPackage
9import me.func.protocol.graffiti.packet.GraffitiLoadUserPackage
10import me.func.protocol.graffiti.packet.GraffitiUsePackage
11import me.func.protocol.personalization.FeatureUserData
12import me.func.protocol.personalization.packet.StickersAvailablePackage
13import ru.cristalix.core.microservice.MicroServicePlatform
14import ru.cristalix.core.microservice.MicroserviceBootstrap
15import ru.cristalix.core.network.Capability
16import ru.cristalix.core.network.CorePackage
17import ru.cristalix.core.network.ISocketClient
18import ru.cristalix.core.network.packages.MoneyTransactionRequestPackage
19import ru.cristalix.core.network.packages.MoneyTransactionResponsePackage
20import ru.cristalix.core.realm.RealmId
21import java.util.*
22import kotlin.concurrent.thread
23
24private val scope = CoroutineScope(Dispatchers.IO)
25private lateinit var mongoAdapter: MongoAdapter
26
27fun syncProfile(player: UUID, data: FeatureUserData? = null) = FeatureUserStorage(player, actualGraffitiPacks.values.map {
28GraffitiPackStorage(
29it.uuid,
30it.graffiti.map { GraffitiUnitStorage(it.uses, it.uuid) }.toMutableList()
31)
32}.toMutableList(), data?.activePack ?: 0, mutableListOf(), null)
33
34fun main() {
35mongoAdapter = MongoAdapter(
36System.getenv("MONGO_URI"), System.getenv("MONGO_DB"), System.getenv("MONGO_COLLECTION")
37)
38
39MicroserviceBootstrap.bootstrap(MicroServicePlatform(2))
40
41ISocketClient.get().registerCapabilities(
42Capability.builder().className(GraffitiBuyPackage::class.java.name).notification(true).build(),
43Capability.builder().className(GraffitiUsePackage::class.java.name).notification(true).build(),
44Capability.builder().className(GraffitiLoadUserPackage::class.java.name).notification(true).build(),
45Capability.builder().className(StickersAvailablePackage::class.java.name).notification(true).build()
46)
47
48registerHandler<StickersAvailablePackage> { _, packet ->
49// Ответ серверу списком доступных стикеров
50packet.list = mutableListOf()
51// TODO: Тут пропущена логика
52ISocketClient.get().write(packet)
53}
54
55val standardProfile = FeatureUserData(
56UUID.randomUUID(), "", actualGraffitiPacks.values.toMutableList(), 0, mutableListOf(), null
57)
58
59registerHandler<GraffitiLoadUserPackage> { realm, packet ->
60// Загрузка профиля игрока
61scope.launch {
62loadProfile(packet.playerUuid) { data ->
63var update: Boolean
64
65// Если данные уже есть - обновляем набор паков, если нет - создаем новые
66packet.data = data?.let {
67println("Loaded data for ${packet.playerUuid}.")
68FeatureUserData(
69it.uuid,
70"",
71it.packs.mapNotNull { it.toFullData() }.toMutableList().apply {
72// Если не хватает новых паков - добавить и сохранить
73val actual =
74actualGraffitiPacks.values.filter { pack -> it.packs.none { it.uuid == pack.uuid } }
75if (actual.isNotEmpty()) {
76update = true
77addAll(actual)
78}
79},
80it.activePack,
81it.stickers,
82it.activeSticker
83)
84} ?: standardProfile.apply {
85uuid = packet.playerUuid
86update = true
87}
88
89packet.data?.packs?.forEach {
90it.graffiti.onEach { it.uses = 50 }
91}
92update = true
93
94// Если данные только что были сгенерированы - сохранить
95if (update) scope.launch { mongoAdapter.save(syncProfile(packet.playerUuid, packet.data)) }
96
97// Ответ серверу
98ISocketClient.get().write(packet)
99println("Wrote graffiti load to ${data?.uuid} from ${realm.realmName}.")
100}
101}
102}
103
104registerHandler<GraffitiBuyPackage> { realm, pckg ->
105// Загрузка профиля игрока
106scope.launch {
107loadProfile(pckg.playerUUID) { userData ->
108// Покупка граффити
109if (userData == null) {
110ISocketClient.get().write(pckg)
111println("Cannot buy pack! UserData is null, player uuid: ${pckg.playerUUID}.")
112} else {
113// Если данные игрока успешно загружены
114pckg.errorMessage = invoice(
115pckg.playerUUID, pckg.price, "Покупка граффити ${pckg.packUUID}"
116).errorMessage
117
118if (pckg.errorMessage.isNullOrEmpty()) {
119// Если покупка прошла успешно
120println("${pckg.playerUUID} payed ${pckg.price} for ${pckg.packUUID}!")
121
122// Начисление граффити
123actualGraffitiPacks[pckg.packUUID]?.apply {
124// Если у игрока нет этого пака - добавить
125if (userData.packs.none { it.uuid == this.uuid }) {
126userData.packs.add(
127GraffitiPackStorage(
128uuid,
129graffiti.map { GraffitiUnitStorage(it.uses, it.uuid) }.toMutableList()
130)
131)
132}
133
134// Выдача граффити
135userData.packs.firstOrNull { uuid == it.uuid }?.data?.forEachIndexed { i, it -> it.uses += graffiti[i].address.maxUses }
136println("${pckg.playerUUID} got ${pckg.packUUID} pack")
137}
138
139// Сохранение данных
140async { mongoAdapter.save(userData) }.invokeOnCompletion {
141if (it == null) println(
142"Successful payment from ${realm.realmName}! ${pckg.playerUUID} bought pack ${
143pckg.packUUID
144}"
145) else {
146println("Payment save error")
147it.printStackTrace()
148}
149}
150}
151
152// Отправка пакета назад
153ISocketClient.get().write(pckg)
154}
155}
156}
157}
158
159registerHandler<GraffitiUsePackage> { realm, pckg ->
160// Загрузка профиля игрока
161scope.launch {
162loadProfile(pckg.playerUUID) { userData ->
163// Если данные игрока успешно загружены
164// Получение пака
165userData?.packs?.firstOrNull { it.uuid == pckg.packUUID }?.let { pack ->
166// pack.data.firstOrNull { it.uuid == pckg.graffitiUUID && it.uses > 0 }?.let {
167pack.data.firstOrNull { it.uuid == pckg.graffitiUUID }?.let {
168// Разрешить ставить граффити если оно есть
169pckg.success = true
170
171// Вычесть игроку одну штуку
172it.uses--
173
174// Сохранить изменение
175mongoAdapter.save(userData)
176println("Player use graffiti from ${realm.realmName}! ${pckg.playerUUID} used ${pckg.packUUID}")
177}
178}
179
180// Ответ серверу об игроке
181ISocketClient.get().write(pckg)
182}
183}
184}
185
186thread {
187while (true) {
188val line = readLine()
189if (line?.startsWith("give ") == true) {
190val uuid = UUID.fromString(line.drop(5))
191scope.launch {
192loadProfile(uuid) { data ->
193if (data != null) {
194data.packs.forEach { pack ->
195pack.data.forEach { unit ->
196unit.uses += 1000
197}
198}
199mongoAdapter.save(data)
200println("Done! $uuid get graffiti...")
201} else {
202println("Player not initialized!")
203}
204}
205}
206}
207}
208}
209}
210
211private suspend fun loadProfile(uuid: UUID, accept: suspend (FeatureUserStorage?) -> (Any)) =
212accept(mongoAdapter.find(uuid) ?: syncProfile(uuid))
213
214private inline fun <reified T : CorePackage> registerHandler(noinline packageHandler: (RealmId, T) -> Unit) =
215ISocketClient.get().addListener(T::class.java, packageHandler)
216
217private suspend fun invoice(user: UUID, price: Int, desc: String): MoneyTransactionResponsePackage =
218coroutineScope {
219async {
220ISocketClient.get().writeAndAwaitResponse<MoneyTransactionResponsePackage>(
221MoneyTransactionRequestPackage(user, price, true, desc)
222).await()
223}
224}.await()
225