Merge branch 'master' into feature-blocklogsandrollback
1
.gitignore
vendored
@ -9,6 +9,7 @@
|
||||
/desktop/mindustry-maps/
|
||||
/desktop/gifexport/
|
||||
/core/lib/
|
||||
/annotations/build/
|
||||
/kryonet/build/
|
||||
/server/build/
|
||||
/android/assets/mindustry-maps/
|
||||
|
@ -38,6 +38,4 @@ After building, the output .JAR file should be in the output JAR file should be
|
||||
|
||||
<a href="https://anuke.itch.io/mindustry"><img src="https://i.imgur.com/sk26hTV.png" width="auto" height="75"></a>
|
||||
|
||||
<a href="https://anuke.itch.io/mindustry"><img src="https://i.imgur.com/ZSPVQpn.gif" width="auto" height="75"></a>
|
||||
|
||||
<a href="https://play.google.com/store/apps/details?id=io.anuke.mindustry&hl=en"><img src="https://i.imgur.com/8dF6l81.png" width="auto" height="75"></a>
|
||||
|
@ -20,7 +20,7 @@ import io.anuke.kryonet.DefaultThreadImpl;
|
||||
import io.anuke.kryonet.KryoClient;
|
||||
import io.anuke.kryonet.KryoServer;
|
||||
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
|
@ -27,7 +27,7 @@ allprojects {
|
||||
gdxVersion = '1.9.8'
|
||||
roboVMVersion = '2.3.0'
|
||||
aiVersion = '1.8.1'
|
||||
uCoreVersion = '55f0d90'
|
||||
uCoreVersion = 'd5af97f93813d8767423521b1fcc5a5e0f7241d9'
|
||||
|
||||
getVersionString = {
|
||||
String buildVersion = getBuildVersion()
|
||||
@ -144,8 +144,7 @@ project(":ios") {
|
||||
}
|
||||
|
||||
robovm {
|
||||
iosSignIdentity = "a"
|
||||
iosProvisioningProfile = ""
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,7 +152,7 @@ project(":core") {
|
||||
apply plugin: "java"
|
||||
|
||||
dependencies {
|
||||
boolean comp = false//System.properties["release"] == null || System.properties["release"] == "false"
|
||||
boolean comp = System.properties["release"] == null || System.properties["release"] == "false"
|
||||
|
||||
if(!comp){
|
||||
println("NOTICE: Compiling release build.")
|
||||
|
@ -1,4 +1,4 @@
|
||||
text.about=Created by [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\nOriginally an entry in the [orange]GDL[] Metal Monstrosity Jam.\n\nCredits:\n- SFX made with [YELLOW]bfxr[]\n- Music made by [GREEN]Roccow[]\n\nSpecial thanks to:\n- [coral]MitchellFJN[]: extensive playtesting and feedback\n- [sky]Luxray5474[]: wiki work, code contributions\n- [lime]Epowerj[]: code build system, icon\n- All the beta testers on itch.io and Google Play\n
|
||||
text.about=Created by [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\nOriginally an entry in the [orange]GDL[] Metal Monstrosity Jam.\n\nCredits:\n- SFX made with [YELLOW]bfxr[]\n- Music made by [GREEN]a beat a day[]\n\nSpecial thanks to:\n- [coral]MitchellFJN[]: extensive playtesting and feedback\n- [sky]Luxray5474[]: wiki work, code contributions\n- [lime]Epowerj[]: code build system, icon\n- All the beta testers on itch.io and Google Play\n
|
||||
text.credits=Credits
|
||||
text.discord=Join the mindustry discord!
|
||||
text.changes=[SCARLET]Attention!\n[]Some important game mechanics have been changed.\n\n- [accent]Teleporters[] now use power.\n- [accent]Smelteries[] and [accent]crucibles[] now have a maximum item capacity.\n- [accent]Crucibles[] now require coal as fuel.
|
||||
@ -107,7 +107,7 @@ text.savefail=Failed to save game!
|
||||
text.save.delete.confirm=Are you sure you want to delete this save?
|
||||
text.save.delete=Delete
|
||||
text.save.export=Export Save
|
||||
text.save.import.invalid=[orange]This save is invalid!
|
||||
text.save.import.invalid=[orange]This save is invalid!\n\nNote that[scarlet]importing saves with custom maps[orange]\nfrom other devices does not work!
|
||||
text.save.import.fail=[crimson]Failed to import save: [orange]{0}
|
||||
text.save.export.fail=[crimson]Failed to export save: [orange]{0}
|
||||
text.save.import=Import Save
|
||||
|
@ -1,44 +1,44 @@
|
||||
text.about = Creado por [ROYAL] Anuken [] - [SKY] anukendev@gmail.com [] Originalmente una entrada en el [naranja] GDL [] Metal Monstrosity Jam. Créditos: - SFX hecho con [AMARILLO] bfxr [] - Música hecha por [VERDE] RoccoW [] / encontrado en [lime] FreeMusicArchive.org [] Agradecimientos especiales a: - [coral] MitchellFJN []: extensa prueba de juego y comentarios - [cielo] Luxray5474 []: trabajo wiki, contribuciones de código - [lime] Epowerj []: sistema de compilación de código, icono - Todos los probadores beta en itch.io y Google Play\n
|
||||
text.about = Creado por [ROYAL]Anuken [] - [SKY] anukendev@gmail.com [] Originalmente una entrada en el [naranja] GDL [] Metal Monstrosity Jam. Créditos: - SFX hecho con [AMARILLO] bfxr [] - Música hecha por [VERDE] RoccoW [] / encontrado en [lime] FreeMusicArchive.org [] Agradecimientos especiales a: - [coral] MitchellFJN []: extensa prueba de juego y comentarios - [cielo] Luxray5474 []: trabajo wiki, contribuciones de código - [lime] Epowerj []: sistema de compilación de código, icono - Todos los probadores beta en itch.io y Google Play\n
|
||||
text.credits = Créditos
|
||||
text.discord = ¡Únete al Discord de Mindustry!
|
||||
text.changes = [SCARLET] ¡Atención! [] Algunas mecánicas importantes del juego han sido cambiadas. - [acento] Los teleportadores [] ahora usan energía. - [acento] Los crisoles de Smelteries [] y [acento] [] ahora tienen una capacidad máxima de artículo. - [acento] Crucibles [] ahora requieren carbón como combustible.
|
||||
text.changes = [SCARLET] ¡Atención! [] Algunas mecánicas importantes del juego han sido cambiadas. - [acento] Los teletransportadores [] ahora usan energía. - [acento]Los talleres de fundición[] y [acento]los crisoles [] ahora tienen una capacidad máxima de artículos. - [acento] Los crisoles[] ahora requieren carbón como combustible.
|
||||
text.link.discord.description = La sala oficial del discord de Mindustry
|
||||
text.link.github.description = Código fuente del juego
|
||||
text.link.dev-builds.description = Desarrollos de desarrollo inestables
|
||||
text.link.dev-builds.description = Estados en desarrollo inestables
|
||||
text.link.trello.description = Tablero trello oficial para las características planificadas
|
||||
text.link.itch.io.description = itch.io página con descargas de PC y versión web
|
||||
text.link.itch.io.description = itch.io és la página con descargas para PC y la versión web
|
||||
text.link.google-play.description = Listado en la tienda de Google Play
|
||||
text.link.wiki.description = Wiki oficial de Mindustry
|
||||
text.linkfail = Error al abrir el enlace! La URL ha sido copiada a su portapapeles
|
||||
text.editor.web = ¡La versión web no es compatible con el editor! Descargue el juego para usarlo.
|
||||
text.multiplayer.web = ¡Esta versión del juego no admite multijugador! Para jugar al modo multijugador desde su navegador, use el enlace \"versión de varios jugadores\" en la página itch.io.
|
||||
text.linkfail = ¡Error al abrir el enlace!\nLa URL ha sido copiada a su portapapeles
|
||||
text.editor.web = ¡La versión web no es compatible con el editor!\nDescargue el juego para usarlo.
|
||||
text.multiplayer.web = ¡Esta versión del juego no admite multijugador!\nPara jugar al modo multijugador desde su navegador, use el enlace \"versión de varios jugadores\" en la página itch.io.
|
||||
text.gameover = El núcleo fue destruido.
|
||||
text.highscore = [YELLOW] ¡Nueva puntuación!
|
||||
text.highscore = [YELLOW]¡Nueva mejor puntuación!
|
||||
text.lasted = Duró hasta la ronda
|
||||
text.level.highscore = Puntuación\nmàs alta: [accent]{0}
|
||||
text.level.highscore = Puntuación màs alta: [accent]
|
||||
text.level.delete.title = Confirmar Eliminación
|
||||
text.level.delete = ¿Seguro que quieres eliminar el mapa \"[ORANGE] \"?
|
||||
text.level.delete = ¿Seguro que quieres eliminar el mapa \"[ORANGE] \" {0}?
|
||||
text.level.select = Selección de nivel
|
||||
text.level.mode = Modo de juego:
|
||||
text.savegame = Guardar Juego
|
||||
text.loadgame = Cargar Juego
|
||||
text.joingame = Unirse a\nun juego
|
||||
text.newgame = Nuevo Juego
|
||||
text.savegame = Guardar Partida
|
||||
text.loadgame = Cargar Partida
|
||||
text.joingame = Unirse a una Partida
|
||||
text.newgame = Nueva Partida
|
||||
text.quit = Salir
|
||||
text.about.button = Acerca de
|
||||
text.name = Nombre
|
||||
text.public = Público
|
||||
text.players = {0} Jugadores en línea
|
||||
text.server.player.host = ANFITRIÓN
|
||||
text.server.player.host = {0} ANFITRIÓN
|
||||
text.players.single = {0} jugador en línea
|
||||
text.server.mismatch = Error de paquete: posible desajuste de la versión cliente / servidor. ¡Asegúrate de que tú y el anfitrión tengas la última versión de Mindustry!
|
||||
text.server.mismatch = Error de paquete: posible desajuste de la versión cliente / servidor.\n¡Asegúrate de que tú y el anfitrión tengáis la última versión de Mindustry!
|
||||
text.server.closing = [accent] Cerrando servidor ...
|
||||
text.server.kicked.kick = ¡Has sido expulsado del servidor!
|
||||
text.server.kicked.invalidPassword = ¡Contraseña inválida!
|
||||
text.server.kicked.clientOutdated = Cliente desactualizado ¡Actualiza tu juego!
|
||||
text.server.kicked.serverOutdated = Servidor desactualizado ¡Pregúntale al anfitrión para actualizar!
|
||||
text.server.kicked.banned = Estás prohibido en este servidor.
|
||||
text.server.kicked.recentKick = Te han kickeado recientemente. Espera antes de conectarte de nuevo.
|
||||
text.server.kicked.serverOutdated = Servidor desactualizado ¡Pidele actualizar al anfitrión!
|
||||
text.server.kicked.banned = Tu entrada está prohibida en este servidor.
|
||||
text.server.kicked.recentKick = Has sido echado recientemente.\nEspera antes de conectarte de nuevo.
|
||||
text.server.connected = se ha unido.
|
||||
text.server.disconnected = se ha desconectado
|
||||
text.nohost = ¡No se puede alojar el servidor en un mapa personalizado!
|
||||
@ -71,7 +71,7 @@ text.server.admins = Admins
|
||||
text.server.admins.none = ¡No se encontraron administradores!
|
||||
text.server.add = Agregar servidor
|
||||
text.server.delete = ¿Seguro que quieres eliminar este servidor?
|
||||
text.server.hostname = ANFITRIÓN
|
||||
text.server.hostname = Anfitrión: {0}
|
||||
text.server.edit = Editar servidor
|
||||
text.server.outdated = [crimson] ¡Servidor obsoleto! []
|
||||
text.server.outdated.client = [carmesí] Cliente desactualizado! []
|
||||
@ -105,23 +105,23 @@ text.save.delete.confirm = ¿Estás seguro de que deseas eliminar este guardado?
|
||||
text.save.delete = Borrar
|
||||
text.save.export = Exportar guardado
|
||||
text.save.import.invalid = [orange] ¡Este guardado es inválido!
|
||||
text.save.import.fail = [crimson] Fallo al importar guardado: [orange]
|
||||
text.save.export.fail = [crimson] Fallo al exportar guardado: [orange]
|
||||
text.save.import.fail = [crimson] Fallo al importar guardado: [orange] {0}
|
||||
text.save.export.fail = [crimson] Fallo al exportar guardado: [orange] {0}
|
||||
text.save.import = Importar Guardado
|
||||
text.save.newslot = Nombre del guardado:
|
||||
text.save.rename = Renombrar
|
||||
text.save.rename.text = Nuevo nombre
|
||||
text.selectslot = Seleccionar una guardado
|
||||
text.slot = [accent] Casilla
|
||||
text.slot = [accent] Casilla {0}
|
||||
text.save.corrupted = [orange] ¡Arhivo de guardado corrupto o inválido!
|
||||
text.empty = <Vacío>
|
||||
text.on = Encendido
|
||||
text.off = Apagado
|
||||
text.save.autosave = Guardado automático:
|
||||
text.save.map = Mapa:
|
||||
text.save.wave = Horda:
|
||||
text.save.difficulty = Dificultad
|
||||
text.save.date = Guardado por última vez:
|
||||
text.save.autosave = Guardado automático: {0}
|
||||
text.save.map = Mapa: {0}
|
||||
text.save.wave = Horda: {0}
|
||||
text.save.difficulty = Dificultad: {0}
|
||||
text.save.date = Guardado por última vez: {0}
|
||||
text.confirm = Confirmar
|
||||
text.delete = Eliiminar
|
||||
text.ok = OK
|
||||
@ -138,28 +138,28 @@ text.changelog.error = [escarlata] ¡Error al obtener el registro de cambios! Co
|
||||
text.changelog.current = [amarillo] [[Versión actual]
|
||||
text.changelog.latest = [naranja] [[Última versión]
|
||||
text.loading = [accent] Cargando...
|
||||
text.wave = [orange] Horda
|
||||
text.wave.waiting = Horda en
|
||||
text.wave = [orange] Horda {0}
|
||||
text.wave.waiting = Horda en {0}
|
||||
text.waiting = Esperando...
|
||||
text.enemies = Enemigos
|
||||
text.enemies.single = Enemigo
|
||||
text.enemies = {0} Enemigos
|
||||
text.enemies.single = {0} Enemigo
|
||||
text.loadimage = Cargar imagen
|
||||
text.saveimage = Guardar imagen
|
||||
text.oregen = Generación\nde mineral
|
||||
text.editor.badsize = [orange]¡Dimensiones de imagen inválidas![]\nDimensiones de mapa válidas:
|
||||
text.editor.errorimageload = Error al cargar el archivo de imagen: [orange]
|
||||
text.editor.errorimagesave = Error al guardar el archivo de imagen: [orange]
|
||||
text.oregen = Generación de mineral {0}
|
||||
text.editor.badsize = [orange]¡Dimensiones de imagen inválidas![]\nDimensiones de mapa válidas: {0}
|
||||
text.editor.errorimageload = Error al cargar el archivo de imagen: [orange] {0}
|
||||
text.editor.errorimagesave = Error al guardar el archivo de imagen: [orange] {0}
|
||||
text.editor.generate = Generar
|
||||
text.editor.resize = Cambiar\ntamaño
|
||||
text.editor.loadmap = Cargar\nmapa
|
||||
text.editor.savemap = Guardar\nmapa
|
||||
text.editor.loadimage = Cargar\nimagen
|
||||
text.editor.saveimage = Guardar\nimagen
|
||||
text.editor.resize = Cambiar tamaño
|
||||
text.editor.loadmap = Cargar mapa
|
||||
text.editor.savemap = Guardar mapa
|
||||
text.editor.loadimage = Cargar imagen
|
||||
text.editor.saveimage = Guardar imagen
|
||||
text.editor.unsaved = [scarlet] ¡Tienes cambios sin guardar! [] ¿Estás seguro de que quieres salir?
|
||||
text.editor.brushsize = Tamaño\ndel pincel:
|
||||
text.editor.brushsize = Tamaño del pincel: {0}
|
||||
text.editor.noplayerspawn = ¡Este mapa no tiene punto de aparición del jugador!
|
||||
text.editor.manyplayerspawns = ¡Los mapas no pueden tener más de un punto de spawn de jugador!
|
||||
text.editor.manyenemyspawns = ¡No puede tener más de puntos de aparición enemiga!
|
||||
text.editor.manyenemyspawns = {0 }¡No puede tener más de puntos de aparición enemiga!
|
||||
text.editor.resizemap = Cambiar el tamaño del mapa
|
||||
text.editor.resizebig = [escarlata] ¡Advertencia! [] Los mapas de más de 256 unidades pueden ser inestables.
|
||||
text.editor.mapname = Nombre del mapa
|
||||
@ -362,7 +362,7 @@ mode.waves.name = Hordas
|
||||
mode.waves.description = El modo normal. Recursos limitados y las hordas vendrán automáticamente
|
||||
mode.sandbox.name = Sandbox
|
||||
mode.sandbox.description = Recursos infinitos y sin temporizador para las olas.
|
||||
mode.freebuild.name = Construcción\nlibre
|
||||
mode.freebuild.name = Construcción libre
|
||||
mode.freebuild.description = Recursos limitados y sin tiempo definido para las hordas
|
||||
upgrade.standard.name = Estandar
|
||||
upgrade.standard.description = El mech estándar.
|
||||
@ -539,14 +539,14 @@ block.sniperturret.fulldescription = Torreta de largo alcance avanzada. Utiliza
|
||||
block.mortarturret.name = Torreta antiaérea
|
||||
block.mortarturret.fulldescription = Torreta avanzada de baja salpicadura de daños por salpicadura. Utiliza carbón para munición. Dispara un aluvión de balas que explotan en metralla. Útil para grandes multitudes de enemigos.
|
||||
block.laserturret.name = Torreta láser
|
||||
block.laserturret.fulldescription = Torreta de un solo objetivo avanzado. Utiliza el poder Buena torrecilla de medio alcance. Solo objetivo único. Nunca falla
|
||||
block.laserturret.fulldescription = Torreta de un solo objetivo avanzado. Utiliza el energia. Buena torre de medio alcance. Objetivo único. Nunca falla
|
||||
block.waveturret.name = Torreta tesla
|
||||
block.waveturret.fulldescription = Torreta multi-objetivo avanzada. Utiliza el poder Rango medio. Nunca falla. Promedio a bajo daño, pero puede golpear a varios enemigos simultáneamente con la iluminación de la cadena.
|
||||
block.waveturret.fulldescription = Torreta multi-objetivo avanzada. Utiliza el poder Rango medio. Nunca falla. De Medio a bajo daño, pero puede golpear a varios enemigos simultáneamente con rayos en cadena.
|
||||
block.plasmaturret.name = Torreta de plasma
|
||||
block.plasmaturret.fulldescription = Versión altamente avanzada de la torreta de fuego. Utiliza carbón como munición. Daño muy alto, rango bajo a medio.
|
||||
block.chainturret.name = Torreta de cadena
|
||||
block.chainturret.fulldescription = La última torreta de fuego rápido. Usa uranio como munición. Dispara babosas grandes a una alta tasa de fuego. Rango medio. Se extiende por múltiples mosaicos. Extremadamente duro.
|
||||
block.chainturret.fulldescription = La torreta de fuego rápido suprema. Usa uranio como munición. Dispara babosas grandes a una alta cadencia. Rango medio. Se extiende por múltiples bloques. Extremadamente duradero.
|
||||
block.titancannon.name = Cañón titán
|
||||
block.titancannon.fulldescription = La torreta suprema de largo alcance. Usa uranio como munición. Dispara grandes proyectiles de daño de área a una velocidad de fuego media. De largo alcance. Se extiende por múltiples bloques. Extremadamente durable.
|
||||
block.titancannon.fulldescription = La torreta de largo alcance suprema. Usa uranio como munición. Dispara grandes proyectiles con daño de área a una cadencia media. De largo alcance. Se extiende por múltiples bloques. Extremadamente duradero.
|
||||
block.playerspawn.name = Punto de aparición del jugador
|
||||
block.enemyspawn.name = Generador de enemigos
|
||||
|
@ -205,7 +205,7 @@ setting.difficulty.easy = łatwy
|
||||
setting.difficulty.normal = normalny
|
||||
setting.difficulty.hard = trudny
|
||||
setting.difficulty.insane = szalony
|
||||
setting.difficulty.purge = Usuń
|
||||
setting.difficulty.purge = Czystka
|
||||
setting.difficulty.name = Poziom trudności
|
||||
setting.screenshake.name = Trzęsienie się ekranu
|
||||
setting.smoothcam.name = Płynna kamera
|
||||
@ -373,8 +373,8 @@ block.titaniumwall-large.name = duża tytanowa ściana
|
||||
block.titaniumwall-large.fulldescription = Silny blok obronny. Rozpiętość wielu płytek.
|
||||
block.duriumwall-large.name = duża ściana z dirium
|
||||
block.duriumwall-large.fulldescription = Bardzo silny blok obronny. Rozpiętość wielu płytek.
|
||||
block.titaniumshieldwall.name = Ściana ekranowana
|
||||
block.titaniumshieldwall.fulldescription = Silny blok obronny z dodatkową wbudowaną tarczą. Wymaga zasilania. Używa energii do pochłaniania pocisków wroga. Zaleca się stosowanie wzmacniaczy energii w celu dostarczenia jej ściany.
|
||||
block.titaniumshieldwall.name = Ściana z polem obronnym
|
||||
block.titaniumshieldwall.fulldescription = Silny blok obronny z dodatkową wbudowaną tarczą. Wymaga zasilania. Używa energii do pochłaniania pocisków wroga. W celu dostarczenia zasilania zaleca się stosowanie wzmacniaczy energii.
|
||||
block.repairturret.name = Wieża naprawcza
|
||||
block.repairturret.fulldescription = Naprawia pobliskie uszkodzone bloki w niedużej prędkości. Wykorzystuje niewielkie ilości energii.
|
||||
block.megarepairturret.name = Wieża naprawcza II
|
@ -1,5 +1,17 @@
|
||||
text.about = Создатель [ROYAL] Anuken. [] \nИзначально игра была создана для участия в [orange] GDL [] MM Jam. \n\nАвторы: \n- Звуковые эффекты, сделаны с помощью [YELLOW] bfxr [] \n- Музыка, создана [GREEN] RoccoW [] / найденная на [lime] FreeMusicArchive.org [] \n\nОсобая благодарность: \n- [coral] MitchellFJN []: в тестировании и отзывах \n- [sky] Luxray5474 []: работа в вики, помощь в разработке \n- Все бета-тестеры на itch.io и Google Play\n\nИгра переведена полностью на русский язык [GREEN]krocotavus[] и [GREEN]lexa1549[]\n
|
||||
text.about = Создатель [ROYAL] Anuken. [] \nИзначально игра была создана для участия в [orange] GDL [] MM Jam. \n\nАвторы: \n- Звуковые эффекты, сделаны с помощью [YELLOW] bfxr [] \n- Музыка, создана [GREEN] RoccoW [] / найденная на [lime] FreeMusicArchive.org [] \n\nОсобая благодарность: \n- [coral] MitchellFJN []: в тестировании и отзывах \n- [sky] Luxray5474 []: работа в вики, помощь в разработке \n- Все бета-тестеры на itch.io и Google Play\n\nИгра переведена полностью на русский язык [GREEN]krocotavus[] и [GREEN]lexa1549. Дополнил перевод [GREEN]Prosta4ok_ua[]\n
|
||||
text.credits = Авторы
|
||||
text.discord = Присоединяйтесь к нашему Discord чату!
|
||||
text.changes=[SCARLET] Внимание!\n[]Изменена некоторая важная игровая механика.\n\n-[accent]Телепортеры[]теперь используют силу.\n-[accent]Печи[]и[accent]тигли[]теперь имеют максимальная емкость элемента.\n-[accent]Тигли[]теперь требует угля в качестве топлива.
|
||||
text.link.discord.description = официальный discord-сервер Mindustry
|
||||
text.link.github.description = Исходный код игры
|
||||
text.link.dev-builds.description = Нестабильные разработки
|
||||
text.link.trello.description = Официальная доска trello для запланированных функций
|
||||
text.link.itch.io.description = itch.io страница с загрузкой ПК и веб-версией
|
||||
text.link.google-play.description = Google Play список магазинов
|
||||
text.link.wiki.description = официальная вики Mindustry
|
||||
text.linkfail = Не удалось открыть ссылку!\nURL-адрес был скопирован в буфер обмена.
|
||||
text.editor.web = Веб-версия не поддерживает редактор!\nЗагрузите игру, чтобы использовать ее.
|
||||
text.multiplayer.web = Эта версия игры не поддерживает многопользовательскую игру! \n Чтобы играть в мультиплеер из своего браузера, используйте ссылку «Многопользовательская веб-версия» на странице itch.io.
|
||||
text.gameover = Ядро было уничтожено.
|
||||
text.highscore = [YELLOW]Новый рекорд!
|
||||
text.lasted = Вы продержались до волны
|
||||
@ -11,19 +23,28 @@ text.level.mode = Режим игры:
|
||||
text.savegame = Сохранить игру
|
||||
text.loadgame = Загрузить игру
|
||||
text.joingame = Присоединиться
|
||||
text.newgame= Новая игра
|
||||
text.quit = Выход
|
||||
text.about.button = Об игре
|
||||
text.name = Название:
|
||||
text.public = Общие
|
||||
text.players = Игроков на сервере: {0}
|
||||
text.server.player.host={0} (хост)
|
||||
text.players.single = {0} игрок на сервере
|
||||
text.server.mismatch = Ошибка пакета: возможное несоответствие версии клиента / сервера. Убедитесь, что у вас и у создателя сервера установлена последняя версия Mindustry!
|
||||
.server.closing = [accent]Закрытие сервера...
|
||||
text.server.closing = [accent]Закрытие сервера...
|
||||
text.server.kicked.kick = Вас выгнали с сервера!
|
||||
text.server.kicked.fastShoot = Вы стреляете слишком быстро.
|
||||
text.server.kicked.invalidPassword = Неверный пароль.
|
||||
text.server.kicked.clientOutdated = Устаревший клиент! Обновите игру!
|
||||
text.server.kicked.serverOutdated = Устаревший сервер! Попросите хост обновить!
|
||||
text.server.kicked.banned = Вы заблокированы на этом сервере.
|
||||
text.server.kicked.recentKick=Вы недавно были кикнуты.\n Подождите немного перед следующим подключением
|
||||
text.server.connected = {0} присоединился
|
||||
text.server.disconnected = {0} отключился.
|
||||
text.nohost = Не удается запустить сервер на пользовательской карте!
|
||||
text.host.info=The [accent]host[] button hosts a server on ports [scarlet]6567[] and [scarlet]6568.[]\nAnybody on the same [LIGHT_GRAY]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[LIGHT_GRAY]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings.
|
||||
text.join.info=Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP.
|
||||
text.hostserver = Запустить сервер
|
||||
text.host = Сервер
|
||||
text.hosting = [accent]Открытие сервера...
|
||||
@ -32,18 +53,46 @@ text.hosts.discovering = Поиск локальных игр
|
||||
text.server.refreshing = Обновление сервера
|
||||
text.hosts.none = [lightgray]Локальных игр не обнаружено!
|
||||
text.host.invalid = [scarlet] Не удается подключиться к хосту.
|
||||
text.server.friendlyfire = Дружественный огонь
|
||||
text.trace = Слежка за игроком
|
||||
text.trace.playername = Имя игрока: [accent]{0}
|
||||
text.trace.ip = IP: [accent]{0}
|
||||
text.trace.id = Уникальный идентификатор: [accent]{0}
|
||||
text.trace.android = Клиент Android: [accent]{0}
|
||||
text.trace.modclient = Пользовательский клиент: [accent]{0}
|
||||
text.trace.totalblocksbroken = Всего разбитых блоков: [accent]{0}
|
||||
|
||||
e.structureblocksbroken = Структурных блоков сломанных: [accent]{0}
|
||||
text.trace.lastblockbroken = Последний сломанный блок:[accent]{0}
|
||||
text.trace.totalblocksplaced = Всего размещено блоков: [accent]{0}
|
||||
text.trace.lastblockplaced = Последний размещенный блок: [accent]{0}
|
||||
text.invalidid = Недопустимый идентификатор клиента! Отправьте отчет об ошибке.
|
||||
text.server.bans = Блокировки
|
||||
text.server.bans.none = Никаких заблокированных игроков не найдено!
|
||||
text.server.admins = Администраторы
|
||||
text.server.admins.none = Администраторов не найдено!
|
||||
text.server.add = Добавить сервер
|
||||
text.server.delete = Вы действительно хотите удалить этот сервер?
|
||||
text.server.hostname = Хост: {0}
|
||||
text.server.edit = Редактировать сервер
|
||||
text.server.outdated = [crimson]Устаревший сервер![]
|
||||
text.server.outdated.client = [crimson]Устаревший клиент![]
|
||||
text.server.version = [lightgray]Версия: {0}
|
||||
text.server.custombuild=[yellow]Пользовательская сборка
|
||||
text.confirmban = Вы действительно хотите заблокировать этого игрока?
|
||||
text.confirmunban = Вы действительно хотите разблокировать этого игрока?
|
||||
text.confirmadmin = Вы уверены, что хотите сделать этого игрока администратором?
|
||||
text.confirmunadmin = Вы действительно хотите удалить статус администратора с этого игрока?
|
||||
text.joingame.byip = Присоединиться по IP ...
|
||||
text.joingame.title = Присоединиться к игре
|
||||
text.joingame.ip = IP:
|
||||
text.disconnect = Отключен\n
|
||||
text.disconnect = Отключён\n
|
||||
text.disconnect.data = Не удалось загрузить данные мира!
|
||||
text.connecting = [accent]Подключение...
|
||||
text.connecting.data = [accent]Загрузка данных мира...
|
||||
text.connectfail = [crimson]Не удалось подключиться к серверу: [orange] {0}
|
||||
text.server.port = Порт:
|
||||
text.server.addressinuse=Адрес уже используется!
|
||||
text.server.invalidport = Неверный номер порта!
|
||||
text.server.error = [crimson]Ошибка создания сервера: [orange] {0}
|
||||
text.tutorial.back = <назад
|
||||
@ -73,6 +122,7 @@ text.off = Выкл
|
||||
text.save.autosave = Автосохранение: {0}
|
||||
text.save.map = Карта: {0}
|
||||
text.save.wave = Волна: {0}
|
||||
text.save.difficulty = Сложность: {0}
|
||||
text.save.date = Последнее сохранение: {0}
|
||||
text.confirm = Подтвердить
|
||||
text.delete = Удалить
|
||||
@ -80,8 +130,16 @@ text.ok = ОК
|
||||
text.open = Открыть
|
||||
text.cancel = Отмена
|
||||
text.openlink = Открыть ссылку
|
||||
text.copylink = Скопировать ссылку
|
||||
text.back = Назад
|
||||
text.quit.confirm = Вы уверены, что хотите выйти?
|
||||
text.changelog.title = Список изменений
|
||||
text.changelog.loading = Получение изменений ...
|
||||
text.changelog.error.android = [orange]Обратите внимание, что журнал изменений иногда не работает на Android 4.4 и ниже!\nЭто связано с внутренней ошибкой Android.
|
||||
text.changelog.error.ios = [orange]В настоящее время журнал изменений не поддерживается iOS.
|
||||
text.changelog.error = [scarlet]Ошибка при получении изменений!\nПроверьте подключение к Интернету.
|
||||
text.changelog.current=[yellow][[Текущая версия]
|
||||
text.changelog.latest=[orange][[Последняя версия]
|
||||
text.loading = [accent] Загрузка...
|
||||
text.wave = [orange]Волна {0}
|
||||
text.wave.waiting = Волна через {0}
|
||||
@ -90,6 +148,7 @@ text.enemies = {0} Противников
|
||||
text.enemies.single = {0} Противник
|
||||
text.loadimage = Загрузить изображение
|
||||
text.saveimage = Сохранить изображение
|
||||
text.oregen = Генерация руд
|
||||
text.editor.badsize = [orange]Недопустимый формат изображения! [] \nДопустимый формат карты: {0}
|
||||
text.editor.errorimageload = Ошибка загрузки изображения: [orange] {0}
|
||||
text.editor.errorimagesave = Ошибка сохранения изображения: [orange] {0}
|
||||
@ -119,6 +178,8 @@ text.menu = Меню
|
||||
text.play = Играть
|
||||
text.load = Загрузить
|
||||
text.save = Сохранить
|
||||
text.language.restart = Перезагрузите игру, чтобы настройки языка вступили в силу.
|
||||
text.settings.language = Язык
|
||||
text.settings = Настройки
|
||||
text.tutorial = Обучение
|
||||
text.editor = Редактор
|
||||
@ -134,6 +195,7 @@ text.purchased = [LIME]Создан!
|
||||
text.weapons = Оружие
|
||||
text.paused = Пауза
|
||||
text.respawn = Возрождение через
|
||||
text.info.title = [accent]Информация
|
||||
text.error.title = [crimson]Произошла ошибка
|
||||
text.error.crashmessage = [SCARLET]Произошла непредвиденная ошибка,которая могла вызвать сбой.[]Пожалуйста, сообщите точные обстоятельства разработчику,при которых эта ошибка возникла : [ORANGE]anukendev@gmail.com[]
|
||||
text.error.crashtitle = Произошла ошибка
|
||||
@ -206,9 +268,12 @@ setting.effects.name = Эффекты на экране
|
||||
setting.sensitivity.name = Чувствительность контроллера
|
||||
setting.saveinterval.name = Интервал автосохранения
|
||||
setting.seconds = {0} Секунд
|
||||
setting.fullscreen.name = Полноэкранный
|
||||
setting.multithread.name = Многопоточность
|
||||
setting.fps.name = Показать FPS
|
||||
setting.vsync.name = Верт. синхронизация
|
||||
setting.lasers.name = Показывать энергетические лазеры
|
||||
setting.previewopacity.name = Прозрачность объкта при предв. просм.
|
||||
setting.healthbars.name = Показать полоски здоровья объекта
|
||||
setting.pixelate.name = Пикселизация экрана
|
||||
setting.musicvol.name = Громкость музыки
|
||||
@ -270,17 +335,23 @@ tutorial.healingTurret.text = Этот лазер можно использов
|
||||
tutorial.healingTurretExplain.text = Пока она имеет заряд, эта турель будет [lime]ремонтировать соседние блоки.[] Когда вы играете, убедитесь, что вы имеете такую на своей базе как можно быстрее.
|
||||
tutorial.smeltery.text = Для многих блоков требуется [orange]сталь[], для этого требуется [orange]плавильный завод[]. Поместите его сюда.
|
||||
tutorial.smelterySetup.text = Этот завод теперь производит [orange]сталь[] из поступающего железа, используя уголь в качестве топлива.
|
||||
tutorial.tunnelExplain.text = Также обратите внимание, что предметы проходят через [orange] туннельный блок [] и появляются на другой стороне, проходя через каменный блок. Имейте в виду, что туннели могут проходить только до двух блоков.
|
||||
tutorial.end.text = На этом обучение закончено! Удачи!
|
||||
text.keybind.title = Переназначить клавиши
|
||||
keybind.move_x.name = движение_x
|
||||
keybind.move_y.name = движение_y
|
||||
keybind.select.name = выбрать
|
||||
keybind.break.name = Разрушить
|
||||
keybind.shootInternal.name = Выстрелить
|
||||
keybind.zoom_hold.name = масштаб_удерживать
|
||||
keybind.zoom.name = масштаб
|
||||
keybind.shoot.name = стрельба
|
||||
keybind.zoom_hold.name = удержание_зума
|
||||
keybind.zoom.name = Приблизить
|
||||
keybind.block_info.name = инфо_о_блоке
|
||||
keybind.menu.name = Меню
|
||||
keybind.pause.name = Пауза
|
||||
keybind.dash.name = Рывок
|
||||
keybind.chat.name = Чат
|
||||
keybind.player_list.name = список_игроков
|
||||
keybind.console.name = консоль
|
||||
keybind.rotate_alt.name = вращать_alt
|
||||
keybind.rotate.name = вращать
|
||||
keybind.weapon_1.name = Оружие_1
|
||||
@ -289,9 +360,13 @@ keybind.weapon_3.name = Оружие_3
|
||||
keybind.weapon_4.name = Оружие_4
|
||||
keybind.weapon_5.name = Оружие_5
|
||||
keybind.weapon_6.name = Оружие_6
|
||||
mode.text.help.title=Описание режимов
|
||||
mode.waves.name = волны
|
||||
mode.waves.description = в нормальном режиме. ограниченные ресурсы и автоматические наступающие волны.
|
||||
mode.sandbox.name = песочница
|
||||
mode.sandbox.description = бесконечные ресурсы и нет таймера для волн.
|
||||
mode.freebuild.name = свободная\nстройка
|
||||
mode.freebuild.description=ограниченные ресурсы и нет таймера для волн.
|
||||
upgrade.standard.name = стандарт
|
||||
upgrade.standard.description = Стандартный мех.
|
||||
upgrade.blaster.name = Бластер
|
||||
@ -319,6 +394,7 @@ liquid.plasma.name = Плазма
|
||||
liquid.lava.name = лава
|
||||
liquid.oil.name = Нефть
|
||||
block.weaponfactory.name = оружейный завод
|
||||
block.weaponfactory.fulldescription=Используется для создания оружия для игрока. Нажмите для использования. Автоматически извлекает ресурсы из ядра.
|
||||
block.air.name = воздух
|
||||
block.blockpart.name = часть блока
|
||||
block.deepwater.name = глубоководье
|
||||
|
BIN
core/assets/music/1.mp3
Normal file → Executable file
BIN
core/assets/music/2.mp3
Normal file → Executable file
BIN
core/assets/music/3.mp3
Normal file → Executable file
BIN
core/assets/music/4.mp3
Normal file → Executable file
BIN
core/assets/music/5.mp3
Executable file
BIN
core/assets/music/6.mp3
Executable file
BIN
core/assets/sprites/icon@2x.icns
Normal file
@ -1,9 +1,13 @@
|
||||
package io.anuke.mindustry;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Pixmap.Filter;
|
||||
import com.badlogic.gdx.graphics.PixmapIO;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.io.BlockLoader;
|
||||
import io.anuke.mindustry.io.BundleLoader;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.ucore.modules.ModuleCore;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
||||
|
@ -12,7 +12,7 @@ import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.effect.Shield;
|
||||
import io.anuke.mindustry.entities.enemies.Enemy;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.net.EditLog;
|
||||
import io.anuke.mindustry.net.ClientDebug;
|
||||
import io.anuke.mindustry.net.ServerDebug;
|
||||
@ -21,6 +21,7 @@ import io.anuke.ucore.entities.EffectEntity;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.OS;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Vars{
|
||||
@ -51,12 +52,17 @@ public class Vars{
|
||||
public static final String discordURL = "https://discord.gg/BKADYds";
|
||||
|
||||
public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases";
|
||||
public static final String macAppDir = UCore.getProperty("user.home") + "/Library/Application Support/";
|
||||
//directory for user-created map data
|
||||
public static final FileHandle customMapDirectory = gwt ? null : UCore.isAssets() ?
|
||||
Gdx.files.local("../../desktop/mindustry-maps") : Gdx.files.local("mindustry-maps/");
|
||||
Gdx.files.local("../../desktop/mindustry-maps") :
|
||||
OS.isMac ? (Gdx.files.absolute(macAppDir).child("maps/")) :
|
||||
Gdx.files.local("mindustry-maps/");
|
||||
//save file directory
|
||||
public static final FileHandle saveDirectory = gwt ? null : UCore.isAssets() ?
|
||||
Gdx.files.local("../../desktop/mindustry-saves") : Gdx.files.local("mindustry-saves/");
|
||||
Gdx.files.local("../../desktop/mindustry-saves") :
|
||||
OS.isMac ? (Gdx.files.absolute(macAppDir).child("saves/")) :
|
||||
Gdx.files.local("mindustry-saves/");
|
||||
//scale of the font
|
||||
public static float fontscale = Math.max(Unit.dp.scl(1f)/2f, 0.5f);
|
||||
//camera zoom displayed on startup
|
||||
@ -99,7 +105,7 @@ public class Vars{
|
||||
|
||||
public static final int tilesize = 8;
|
||||
|
||||
public static final Locale[] locales = {new Locale("en"), new Locale("fr"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl", "PL"),
|
||||
public static final Locale[] locales = {new Locale("en"), new Locale("fr"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl"),
|
||||
new Locale("de"), new Locale("pt", "BR"), new Locale("ko"), new Locale("in", "ID"), new Locale("ita"), new Locale("es")};
|
||||
|
||||
public static final Color[] playerColors = {
|
||||
|
@ -13,7 +13,6 @@ import io.anuke.mindustry.input.AndroidInput;
|
||||
import io.anuke.mindustry.input.DefaultKeybinds;
|
||||
import io.anuke.mindustry.input.DesktopInput;
|
||||
import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.io.Saves;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.resource.Item;
|
||||
@ -25,7 +24,9 @@ import io.anuke.ucore.core.Inputs.DeviceType;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
import io.anuke.ucore.modules.Module;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.*;
|
||||
import io.anuke.ucore.util.Atlas;
|
||||
import io.anuke.ucore.util.InputProxy;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@ -102,7 +103,7 @@ public class Control extends Module{
|
||||
|
||||
Sounds.setFalloff(9000f);
|
||||
|
||||
Musics.load("1.mp3", "2.mp3", "3.mp3", "4.mp3");
|
||||
Musics.load("1.mp3", "2.mp3", "3.mp3", "4.mp3", "5.mp3", "6.mp3");
|
||||
|
||||
DefaultKeybinds.load();
|
||||
|
||||
@ -385,7 +386,7 @@ public class Control extends Module{
|
||||
|
||||
if(respawntime > 0){
|
||||
|
||||
respawntime -= delta();
|
||||
respawntime -= Timers.delta();
|
||||
|
||||
if(respawntime <= 0){
|
||||
player.set(world.getSpawnX(), world.getSpawnY());
|
||||
|
@ -11,7 +11,6 @@ import io.anuke.mindustry.entities.BulletType;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.SyncEntity;
|
||||
import io.anuke.mindustry.entities.enemies.Enemy;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.Net.SendMode;
|
||||
import io.anuke.mindustry.net.NetworkIO;
|
||||
|
@ -5,7 +5,6 @@ import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.SyncEntity;
|
||||
import io.anuke.mindustry.game.EventType.GameOverEvent;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||
|
@ -1,10 +1,12 @@
|
||||
package io.anuke.mindustry.io;
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Base64Coder;
|
||||
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.entities.Entity;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
|
||||
import java.util.Date;
|
||||
@ -12,26 +14,40 @@ import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class Platform {
|
||||
/**Each separate game platform should set this instance to their own implementation.*/
|
||||
public static Platform instance = new Platform() {};
|
||||
|
||||
/**Format the date using the default date formatter.*/
|
||||
public String format(Date date){return "invalid";}
|
||||
/**Format a number by adding in commas or periods where needed.*/
|
||||
public String format(int number){return "invalid";}
|
||||
/**Show a native error dialog.*/
|
||||
public void showError(String text){}
|
||||
/**Add a text input dialog that should show up after the field is tapped.*/
|
||||
public void addDialog(TextField field){
|
||||
addDialog(field, 16);
|
||||
}
|
||||
/**See addDialog().*/
|
||||
public void addDialog(TextField field, int maxLength){}
|
||||
/**Update discord RPC.*/
|
||||
public void updateRPC(){}
|
||||
/**Called when the game is exited.*/
|
||||
public void onGameExit(){}
|
||||
/**Open donation dialog. Currently android only.*/
|
||||
public void openDonations(){}
|
||||
/**Whether discord RPC is supported.*/
|
||||
public boolean hasDiscord(){return true;}
|
||||
/**Request Android permissions for writing files.*/
|
||||
public void requestWritePerms(){}
|
||||
/**Return the localized name for the locale. This is basically a workaround for GWT not supporting getName().*/
|
||||
public String getLocaleName(Locale locale){
|
||||
return locale.toString();
|
||||
}
|
||||
/**Whether joining games is supported.*/
|
||||
public boolean canJoinGame(){
|
||||
return true;
|
||||
}
|
||||
/**Whether debug mode is enabled.*/
|
||||
public boolean isDebug(){return false;}
|
||||
/**Must be 8 bytes in length.*/
|
||||
public byte[] getUUID(){
|
||||
@ -46,6 +62,19 @@ public abstract class Platform {
|
||||
}
|
||||
return Base64Coder.decode(uuid);
|
||||
}
|
||||
/**Only used for iOS or android: open the share menu for a map or save.*/
|
||||
public void shareFile(FileHandle file){}
|
||||
|
||||
/**Show a file chooser. Desktop only.
|
||||
*
|
||||
* @param text File chooser title text
|
||||
* @param content Type of files to be loaded
|
||||
* @param cons Selection listener
|
||||
* @param open Whether to open or save files.
|
||||
* @param filetype File extensions to filter.
|
||||
*/
|
||||
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, String filetype){}
|
||||
/**Use the default thread provider from the kryonet module for this.*/
|
||||
public ThreadProvider getThreadProvider(){
|
||||
return new ThreadProvider() {
|
||||
@Override public boolean isOnThread() {return true;}
|
@ -7,7 +7,6 @@ import com.badlogic.gdx.graphics.Colors;
|
||||
import com.badlogic.gdx.math.Interpolation;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.mapeditor.MapEditorDialog;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
import io.anuke.mindustry.ui.fragments.*;
|
||||
|
@ -46,9 +46,9 @@ public class GestureHandler extends GestureAdapter{
|
||||
public boolean pan(float x, float y, float deltaX, float deltaY){
|
||||
if(control.showCursor() && !Inputs.keyDown("select")) return false;
|
||||
|
||||
if(!control.showCursor() && !(control.input().recipe != null
|
||||
if((!control.showCursor() && !(control.input().recipe != null
|
||||
&& control.input().placeMode.lockCamera && state.inventory.hasItems(control.input().recipe.requirements)) &&
|
||||
!(control.input().recipe == null && control.input().breakMode.lockCamera)){
|
||||
!(control.input().recipe == null && control.input().breakMode.lockCamera)) && !ui.hasMouse(x, y)){
|
||||
float dx = deltaX*Core.camera.zoom/Core.cameraScale, dy = deltaY*Core.camera.zoom/Core.cameraScale;
|
||||
player.x -= dx;
|
||||
player.y += dy;
|
||||
|
@ -3,6 +3,7 @@ package io.anuke.mindustry.io;
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.I18NBundle;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package io.anuke.mindustry.io;
|
||||
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.game.Difficulty;
|
||||
import io.anuke.mindustry.game.GameMode;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
|
@ -86,7 +86,7 @@ public class Saves {
|
||||
current = slot;
|
||||
}
|
||||
|
||||
public void importSave(FileHandle file) throws IOException{
|
||||
public SaveSlot importSave(FileHandle file) throws IOException{
|
||||
SaveSlot slot = new SaveSlot(nextSlot);
|
||||
slot.importFile(file);
|
||||
nextSlot ++;
|
||||
@ -94,6 +94,7 @@ public class Saves {
|
||||
saves.add(slot);
|
||||
slot.meta = SaveIO.getData(slot.index);
|
||||
current = slot;
|
||||
return slot;
|
||||
}
|
||||
|
||||
public Array<SaveSlot> getSaveSlots(){
|
||||
|
@ -1,11 +1,11 @@
|
||||
package io.anuke.mindustry.mapeditor;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.graphics.Pixmap;
|
||||
import com.badlogic.gdx.graphics.Texture;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.ui.dialogs.FileChooser;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.ColorMapper;
|
||||
import io.anuke.mindustry.world.ColorMapper.BlockPair;
|
||||
@ -42,7 +42,6 @@ public class MapEditorDialog extends Dialog{
|
||||
private MapSaveDialog saveDialog;
|
||||
private MapResizeDialog resizeDialog;
|
||||
private ScrollPane pane;
|
||||
private FileChooser openFile, saveFile;
|
||||
private boolean saved = false;
|
||||
|
||||
private ButtonGroup<ImageButton> blockgroup;
|
||||
@ -55,42 +54,6 @@ public class MapEditorDialog extends Dialog{
|
||||
dialog = new MapGenerateDialog(editor);
|
||||
view = new MapView(editor);
|
||||
|
||||
openFile = new FileChooser("$text.loadimage", FileChooser.pngFilter, true, file -> {
|
||||
ui.loadfrag.show();
|
||||
Timers.run(3f, () -> {
|
||||
try{
|
||||
Pixmap pixmap = new Pixmap(file);
|
||||
if(verifySize(pixmap)){
|
||||
editor.setPixmap(pixmap);
|
||||
view.clearStack();
|
||||
}else{
|
||||
ui.showError(Bundles.format("text.editor.badsize", Arrays.toString(MapEditor.validMapSizes)));
|
||||
}
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
|
||||
Log.err(e);
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
});
|
||||
});
|
||||
|
||||
saveFile = new FileChooser("$saveimage", false, file -> {
|
||||
if(!file.extension().toLowerCase().equals(".png")){
|
||||
file = file.parent().child(file.nameWithoutExtension() + ".png");
|
||||
}
|
||||
FileHandle result = file;
|
||||
ui.loadfrag.show();
|
||||
Timers.run(3f, () -> {
|
||||
try{
|
||||
Pixmaps.write(editor.pixmap(), result);
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
|
||||
if(!mobile) Log.err(e);
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
});
|
||||
});
|
||||
|
||||
loadDialog = new MapLoadDialog(map -> {
|
||||
saveDialog.setFieldText(map.name);
|
||||
ui.loadfrag.show();
|
||||
@ -237,16 +200,46 @@ public class MapEditorDialog extends Dialog{
|
||||
).text("$text.editor.savemap");
|
||||
|
||||
row();
|
||||
|
||||
//iOS does not support loading raw files.
|
||||
if(!ios) {
|
||||
|
||||
new imagebutton("icon-load-image", isize, () -> {
|
||||
Platform.instance.showFileChooser(Bundles.get("text.loadimage"), "Image Files", MapEditorDialog.this::tryLoadMap, true, "png");
|
||||
}).text("$text.editor.loadimage");
|
||||
|
||||
row();
|
||||
}
|
||||
|
||||
new imagebutton("icon-load-image", isize, () ->
|
||||
openFile.show()
|
||||
).text("$text.editor.loadimage");
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-save-image", isize, () ->
|
||||
saveFile.show()
|
||||
).text("$text.editor.saveimage");
|
||||
new imagebutton("icon-save-image", isize, () -> {
|
||||
//iOS doesn't really support saving raw files. Sharing is used instead.
|
||||
if(!ios){
|
||||
Platform.instance.showFileChooser(Bundles.get("text.saveimage"), "Image Files", file -> {
|
||||
if(!file.extension().toLowerCase().equals(".png")){
|
||||
file = file.parent().child(file.nameWithoutExtension() + ".png");
|
||||
}
|
||||
FileHandle result = file;
|
||||
ui.loadfrag.show();
|
||||
Timers.run(3f, () -> {
|
||||
try{
|
||||
Pixmaps.write(editor.pixmap(), result);
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
|
||||
if(!mobile) Log.err(e);
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
});
|
||||
}, false, "png");
|
||||
}else{
|
||||
try{
|
||||
FileHandle file = Gdx.files.local(("map-" + ((editor.getMap().name == null) ? "unknown" : editor.getMap().name) + ".png"));
|
||||
Pixmaps.write(editor.pixmap(), file);
|
||||
Platform.instance.shareFile(file);
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
|
||||
}
|
||||
}
|
||||
}).text("$text.editor.saveimage");
|
||||
|
||||
row();
|
||||
|
||||
@ -329,6 +322,25 @@ public class MapEditorDialog extends Dialog{
|
||||
}}.grow().end();
|
||||
}
|
||||
|
||||
public void tryLoadMap(FileHandle file){
|
||||
ui.loadfrag.show();
|
||||
Timers.runTask(3f, () -> {
|
||||
try{
|
||||
Pixmap pixmap = new Pixmap(file);
|
||||
if(verifySize(pixmap)){
|
||||
editor.setPixmap(pixmap);
|
||||
view.clearStack();
|
||||
}else{
|
||||
ui.showError(Bundles.format("text.editor.badsize", Arrays.toString(MapEditor.validMapSizes)));
|
||||
}
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
|
||||
Log.err(e);
|
||||
}
|
||||
ui.loadfrag.hide();
|
||||
});
|
||||
}
|
||||
|
||||
private void doInput(){
|
||||
//tool select
|
||||
for(int i = 0; i < EditorTool.values().length; i ++){
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.anuke.mindustry.mapeditor;
|
||||
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.Map;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
|
@ -9,7 +9,7 @@ import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.IntMap;
|
||||
import com.badlogic.gdx.utils.ObjectMap;
|
||||
import com.badlogic.gdx.utils.reflect.ClassReflection;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.net.Packet.ImportantPacket;
|
||||
import io.anuke.mindustry.net.Packet.UnimportantPacket;
|
||||
import io.anuke.mindustry.net.Streamable.StreamBegin;
|
||||
|
@ -2,16 +2,20 @@ package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import io.anuke.mindustry.ui.Links;
|
||||
import io.anuke.mindustry.ui.Links.LinkEntry;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ios;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
|
||||
public class AboutDialog extends FloatingDialog {
|
||||
private static ObjectSet<String> bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds", "trello");
|
||||
|
||||
public AboutDialog(){
|
||||
super("$text.about.button");
|
||||
@ -25,6 +29,10 @@ public class AboutDialog extends FloatingDialog {
|
||||
ScrollPane pane = new ScrollPane(in, "clear");
|
||||
|
||||
for(LinkEntry link : Links.getLinks()){
|
||||
if((ios || OS.isMac) && bannedItems.contains(link.name)){ //because Apple doesn't like me mentioning things
|
||||
continue;
|
||||
}
|
||||
|
||||
Table table = new Table("button");
|
||||
table.margin(0);
|
||||
table.table(img -> {
|
||||
@ -59,10 +67,14 @@ public class AboutDialog extends FloatingDialog {
|
||||
content().add(pane).growX();
|
||||
|
||||
buttons().addButton("$text.credits", this::showCredits).size(200f, 64f);
|
||||
buttons().addButton("$text.changelog.title", ui.changelog::show).size(200f, 64f);
|
||||
|
||||
if(!ios && !OS.isMac){
|
||||
buttons().addButton("$text.changelog.title", ui.changelog::show).size(200f, 64f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void showCredits(){
|
||||
public void showCredits(){
|
||||
FloatingDialog dialog = new FloatingDialog("$text.credits");
|
||||
dialog.addCloseButton();
|
||||
dialog.content().add("$text.about");
|
||||
|
@ -10,6 +10,9 @@ import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import static io.anuke.mindustry.Vars.ios;
|
||||
|
||||
public class ChangelogDialog extends FloatingDialog{
|
||||
private final float vw = 600;
|
||||
@ -22,13 +25,15 @@ public class ChangelogDialog extends FloatingDialog{
|
||||
|
||||
content().add("$text.changelog.loading");
|
||||
|
||||
Changelogs.getChangelog(result -> {
|
||||
versions = result;
|
||||
Gdx.app.postRunnable(this::setup);
|
||||
}, t -> {
|
||||
Log.err(t);
|
||||
Gdx.app.postRunnable(this::setup);
|
||||
});
|
||||
if(!ios && !OS.isMac) {
|
||||
Changelogs.getChangelog(result -> {
|
||||
versions = result;
|
||||
Gdx.app.postRunnable(this::setup);
|
||||
}, t -> {
|
||||
Log.err(t);
|
||||
Gdx.app.postRunnable(this::setup);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void setup(){
|
||||
@ -45,12 +50,16 @@ public class ChangelogDialog extends FloatingDialog{
|
||||
table.add("$text.changelog.error.android").padTop(8);
|
||||
}
|
||||
|
||||
if(Vars.ios){
|
||||
if(ios){
|
||||
table.row();
|
||||
table.add("$text.changelog.error.ios").padTop(8);
|
||||
}
|
||||
}else{
|
||||
for(VersionInfo info : versions){
|
||||
String desc = info.description;
|
||||
|
||||
desc = desc.replace("Android", "Mobile");
|
||||
|
||||
Table in = new Table("clear");
|
||||
in.top().left().margin(10);
|
||||
|
||||
@ -63,7 +72,7 @@ public class ChangelogDialog extends FloatingDialog{
|
||||
in.add("$text.changelog.latest");
|
||||
}
|
||||
in.row();
|
||||
in.labelWrap("[lightgray]" + info.description).width(vw - 20).padTop(12);
|
||||
in.labelWrap("[lightgray]" + desc).width(vw - 20).padTop(12);
|
||||
|
||||
table.add(in).width(vw).pad(8).row();
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import com.badlogic.gdx.graphics.g2d.GlyphLayout;
|
||||
import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Pools;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.ucore.UCore;
|
||||
import io.anuke.ucore.core.Core;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
@ -15,12 +16,14 @@ import io.anuke.ucore.scene.event.Touchable;
|
||||
import io.anuke.ucore.scene.ui.*;
|
||||
import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class FileChooser extends FloatingDialog {
|
||||
private Table files;
|
||||
private FileHandle homeDirectory = Gdx.files.absolute(Gdx.files.getExternalStoragePath());
|
||||
private FileHandle homeDirectory = Gdx.files.absolute(OS.isMac ? UCore.getProperty("user.home") + "/Downloads/" :
|
||||
Gdx.files.getExternalStoragePath());
|
||||
private FileHandle directory = homeDirectory;
|
||||
private ScrollPane pane;
|
||||
private TextField navigation, filefield;
|
||||
@ -96,6 +99,11 @@ public class FileChooser extends FloatingDialog {
|
||||
updateFiles(true);
|
||||
});
|
||||
|
||||
//Macs are confined to the Downloads/ directory
|
||||
if(OS.isMac){
|
||||
up.setDisabled(true);
|
||||
}
|
||||
|
||||
ImageButton back = new ImageButton("icon-arrow-left");
|
||||
back.resizeImage(isize);
|
||||
|
||||
@ -166,7 +174,8 @@ public class FileChooser extends FloatingDialog {
|
||||
|
||||
private void updateFiles(boolean push){
|
||||
if(push) stack.push(directory);
|
||||
navigation.setText(directory.toString());
|
||||
//if is mac, don't display extra info since you can only ever go to downloads
|
||||
navigation.setText(OS.isMac ? directory.name() : directory.toString());
|
||||
|
||||
GlyphLayout layout = Pools.obtain(GlyphLayout.class);
|
||||
|
||||
@ -181,23 +190,25 @@ public class FileChooser extends FloatingDialog {
|
||||
Pools.free(layout);
|
||||
|
||||
files.clearChildren();
|
||||
files.top().left();
|
||||
FileHandle[] names = getFileNames();
|
||||
|
||||
Image upimage = new Image("icon-folder-parent");
|
||||
//macs are confined to the Downloads/ directory
|
||||
if(!OS.isMac) {
|
||||
Image upimage = new Image("icon-folder-parent");
|
||||
TextButton upbutton = new TextButton(".." + directory.toString());
|
||||
upbutton.clicked(() -> {
|
||||
directory = directory.parent();
|
||||
updateFiles(true);
|
||||
});
|
||||
|
||||
TextButton upbutton = new TextButton(".." + directory.toString());
|
||||
upbutton.clicked(()->{
|
||||
directory = directory.parent();
|
||||
updateFiles(true);
|
||||
});
|
||||
|
||||
upbutton.left().add(upimage).padRight(4f).size(14*2);
|
||||
upbutton.getCells().reverse();
|
||||
|
||||
files.top().left().add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2);
|
||||
upbutton.getLabel().setAlignment(Align.left);
|
||||
upbutton.left().add(upimage).padRight(4f).size(14 * 2);
|
||||
upbutton.getLabel().setAlignment(Align.left);
|
||||
upbutton.getCells().reverse();
|
||||
|
||||
files.row();
|
||||
files.add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2);
|
||||
files.row();
|
||||
}
|
||||
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<TextButton>();
|
||||
group.setMinCheckCount(0);
|
||||
|
@ -4,7 +4,7 @@ import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.net.Host;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.scene.ui.ButtonGroup;
|
||||
import io.anuke.ucore.scene.ui.ScrollPane;
|
||||
|
@ -1,7 +1,10 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.io.SaveIO;
|
||||
import io.anuke.mindustry.io.Saves.SaveSlot;
|
||||
import io.anuke.ucore.core.Core;
|
||||
@ -83,14 +86,24 @@ public class LoadDialog extends FloatingDialog{
|
||||
|
||||
if(!gwt) {
|
||||
t.addImageButton("icon-save", "empty", 14 * 3, () -> {
|
||||
new FileChooser("$text.save.export", false, file -> {
|
||||
try {
|
||||
slot.exportFile(file);
|
||||
setup();
|
||||
} catch (IOException e) {
|
||||
ui.showError(Bundles.format("text.save.export.fail", Strings.parseException(e, false)));
|
||||
}
|
||||
}).show();
|
||||
if(!ios) {
|
||||
Platform.instance.showFileChooser(Bundles.get("text.save.export"), "Mindustry Save", file -> {
|
||||
try {
|
||||
slot.exportFile(file);
|
||||
setup();
|
||||
} catch (IOException e) {
|
||||
ui.showError(Bundles.format("text.save.export.fail", Strings.parseException(e, false)));
|
||||
}
|
||||
}, false, "mins");
|
||||
}else{
|
||||
try {
|
||||
FileHandle file = Gdx.files.local("save-" + slot.getName() + ".mins");
|
||||
slot.exportFile(file);
|
||||
Platform.instance.shareFile(file);
|
||||
}catch (Exception e){
|
||||
ui.showError(Bundles.format("text.save.export.fail", Strings.parseException(e, false)));
|
||||
}
|
||||
}
|
||||
}).size(14 * 3).right();
|
||||
}
|
||||
|
||||
@ -134,10 +147,10 @@ public class LoadDialog extends FloatingDialog{
|
||||
|
||||
slots.row();
|
||||
|
||||
if(gwt) return;
|
||||
if(gwt || ios) return;
|
||||
|
||||
slots.addImageTextButton("$text.save.import", "icon-add", "clear", 14*3, () -> {
|
||||
new FileChooser("$text.save.import", f -> f.extension().equals("mins"), true, file -> {
|
||||
Platform.instance.showFileChooser(Bundles.get("text.save.import"), "Mindustry Save", file -> {
|
||||
if(SaveIO.isSaveValid(file)){
|
||||
try{
|
||||
control.getSaves().importSave(file);
|
||||
@ -148,30 +161,34 @@ public class LoadDialog extends FloatingDialog{
|
||||
}else{
|
||||
ui.showError("$text.save.import.invalid");
|
||||
}
|
||||
}).show();
|
||||
}, true, "mins");
|
||||
}).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4);
|
||||
}
|
||||
|
||||
public void runLoadSave(SaveSlot slot){
|
||||
ui.loadfrag.show();
|
||||
|
||||
Timers.runTask(3f, () -> {
|
||||
ui.loadfrag.hide();
|
||||
hide();
|
||||
try{
|
||||
slot.load();
|
||||
state.set(State.playing);
|
||||
ui.paused.hide();
|
||||
}catch(Exception e){
|
||||
Log.err(e);
|
||||
ui.paused.hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
ui.showError("$text.save.corrupted");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void modifyButton(TextButton button, SaveSlot slot){
|
||||
button.clicked(() -> {
|
||||
if(!button.childrenPressed()){
|
||||
ui.loadfrag.show();
|
||||
|
||||
Timers.runTask(3f, () -> {
|
||||
ui.loadfrag.hide();
|
||||
hide();
|
||||
try{
|
||||
slot.load();
|
||||
state.set(State.playing);
|
||||
ui.paused.hide();
|
||||
}catch(Exception e){
|
||||
Log.err(e);
|
||||
ui.paused.hide();
|
||||
state.set(State.menu);
|
||||
logic.reset();
|
||||
ui.showError("$text.save.corrupted");
|
||||
}
|
||||
});
|
||||
runLoadSave(slot);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import com.badlogic.gdx.utils.Align;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetEvents;
|
||||
import io.anuke.ucore.core.Core;
|
||||
|
@ -2,13 +2,14 @@ package io.anuke.mindustry.ui.fragments;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.ui.MenuButton;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.ucore.scene.builders.imagebutton;
|
||||
import io.anuke.ucore.scene.builders.label;
|
||||
import io.anuke.ucore.scene.builders.table;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@ -44,7 +45,13 @@ public class MenuFragment implements Fragment{
|
||||
|
||||
add(new MenuButton("icon-info", "$text.about.button", ui.about::show));
|
||||
|
||||
add(new MenuButton("icon-menu", "$text.changelog.title", ui.changelog::show));
|
||||
add(new MenuButton("icon-menu", OS.isMac ? "$text.credits" : "$text.changelog.title", () -> {
|
||||
if(OS.isMac){
|
||||
ui.about.showCredits();
|
||||
}else {
|
||||
ui.changelog.show();
|
||||
}
|
||||
}));
|
||||
|
||||
row();
|
||||
|
||||
@ -57,7 +64,8 @@ public class MenuFragment implements Fragment{
|
||||
|
||||
}else {
|
||||
new table() {{
|
||||
defaults().size(120f).pad(5);
|
||||
float size = 120f;
|
||||
defaults().size(size).pad(5);
|
||||
float isize = 14f * 4;
|
||||
|
||||
new imagebutton("icon-play-2", isize, ui.levels::show).text("$text.play").padTop(4f);
|
||||
@ -70,13 +78,21 @@ public class MenuFragment implements Fragment{
|
||||
|
||||
row();
|
||||
|
||||
new imagebutton("icon-editor", isize, ui.editor::show).text("$text.editor").padTop(4f);
|
||||
new table(){{
|
||||
|
||||
new imagebutton("icon-tools", isize, ui.settings::show).text("$text.settings").padTop(4f);
|
||||
defaults().size(size).pad(5);
|
||||
|
||||
new imagebutton("icon-info", isize, ui.about::show).text("$text.about.button").padTop(4f);
|
||||
new imagebutton("icon-editor", isize, ui.editor::show).text("$text.editor").padTop(4f);
|
||||
|
||||
new imagebutton("icon-donate", isize, Platform.instance::openDonations).text("$text.donate").padTop(4f);
|
||||
new imagebutton("icon-tools", isize, ui.settings::show).text("$text.settings").padTop(4f);
|
||||
|
||||
new imagebutton("icon-info", isize, ui.about::show).text("$text.about.button").padTop(4f);
|
||||
|
||||
if (!ios) {
|
||||
new imagebutton("icon-donate", isize, Platform.instance::openDonations).text("$text.donate").padTop(4f);
|
||||
}
|
||||
|
||||
}}.colspan(4).end();
|
||||
}}.end();
|
||||
}
|
||||
}}.end();
|
||||
|
@ -33,6 +33,7 @@ public class PlayerListFragment implements Fragment{
|
||||
public void build(){
|
||||
new table(){{
|
||||
new table("pane"){{
|
||||
touchable(Touchable.enabled);
|
||||
margin(14f);
|
||||
new label(() -> Bundles.format(playerGroup.size() == 1 ? "text.players.single" :
|
||||
"text.players", playerGroup.size()));
|
||||
|
@ -86,7 +86,7 @@ task packrCmd() {
|
||||
|
||||
commandLine("java", "-jar", PACKR_DIR + "packr.jar",
|
||||
"--verbose",
|
||||
"--bundle", getPackage(),
|
||||
"--bundle", getPackage() + ".mac",
|
||||
"--platform", getPlatform(),
|
||||
"--executable", appName,
|
||||
"--output", "packr-out/",
|
||||
|
@ -1,12 +1,15 @@
|
||||
package io.anuke.mindustry.desktop;
|
||||
|
||||
import com.badlogic.gdx.Files.FileType;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
|
||||
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
|
||||
import io.anuke.kryonet.KryoClient;
|
||||
import io.anuke.kryonet.KryoServer;
|
||||
import io.anuke.mindustry.Mindustry;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.UCore;
|
||||
import io.anuke.ucore.util.OS;
|
||||
|
||||
public class DesktopLauncher {
|
||||
|
||||
@ -18,6 +21,10 @@ public class DesktopLauncher {
|
||||
config.setWindowedMode(960, 540);
|
||||
config.setWindowIcon("sprites/icon.png");
|
||||
|
||||
if(OS.isMac) {
|
||||
config.setPreferencesConfig(UCore.getProperty("user.home") + "/Library/Application Support/Mindustry", FileType.Absolute);
|
||||
}
|
||||
|
||||
Platform.instance = new DesktopPlatform(arg);
|
||||
|
||||
Net.setClientProvider(new KryoClient());
|
||||
|
@ -3,14 +3,17 @@ package io.anuke.mindustry.desktop;
|
||||
import club.minnced.discord.rpc.DiscordEventHandlers;
|
||||
import club.minnced.discord.rpc.DiscordRPC;
|
||||
import club.minnced.discord.rpc.DiscordRichPresence;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Base64Coder;
|
||||
import io.anuke.kryonet.DefaultThreadImpl;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.ui.dialogs.FileChooser;
|
||||
import io.anuke.ucore.UCore;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
|
||||
import javax.swing.*;
|
||||
@ -40,6 +43,11 @@ public class DesktopPlatform extends Platform {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, String filter) {
|
||||
new FileChooser(text, file -> file.extension().equalsIgnoreCase(filter), open, cons).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format(Date date){
|
||||
return format.format(date);
|
||||
|
@ -16,7 +16,7 @@ import com.google.gwt.i18n.client.NumberFormat;
|
||||
import com.google.gwt.i18n.shared.DateTimeFormat;
|
||||
import com.google.gwt.user.client.ui.*;
|
||||
import io.anuke.mindustry.Mindustry;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
|
||||
|
@ -6,7 +6,7 @@ import com.badlogic.gdx.utils.reflect.ClassReflection;
|
||||
import com.badlogic.gdx.utils.reflect.ReflectionException;
|
||||
import com.sksamuel.gwt.websockets.Websocket;
|
||||
import com.sksamuel.gwt.websockets.WebsocketListener;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Net.ClientProvider;
|
||||
import io.anuke.mindustry.net.Net.SendMode;
|
||||
|
@ -12,12 +12,16 @@
|
||||
<string>${app.id}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>9.0.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${app.name}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>${app.version}</string>
|
||||
<key>CFBundleIconName</key>
|
||||
<string>AppIcon</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
@ -28,6 +32,10 @@
|
||||
<false/>
|
||||
<key>UIStatusBarHidden</key>
|
||||
<true/>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<true/>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
<string>Mindustry</string>
|
||||
<key>UIDeviceFamily</key>
|
||||
<array>
|
||||
<integer>1</integer>
|
||||
@ -43,16 +51,60 @@
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CFBundleIcons</key>
|
||||
|
||||
<key>CFBundleDocumentTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeIconFiles</key>
|
||||
<array>
|
||||
<string>icon-72.png</string>
|
||||
</array>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Mindustry Map File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>LSHandlerRank</key>
|
||||
<string>Owner</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array>
|
||||
<string>public.png</string>
|
||||
<string>io.anuke.mindustry.savefile</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Mindustry Save File</string>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>io.anuke.mindustry.savefile</string>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<string>mins</string>
|
||||
<key>public.mime-type</key>
|
||||
<string>mindustry/mins</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
<!--<key>CFBundleIcons</key>
|
||||
<dict>
|
||||
<key>CFBundlePrimaryIcon</key>
|
||||
<dict>
|
||||
<key>CFBundleIconFiles</key>
|
||||
<array>
|
||||
<string>Icon</string>
|
||||
<string>Icon-72</string>
|
||||
<string>icon</string>
|
||||
<string>icon-72</string>
|
||||
<string>icon-120</string>
|
||||
<string>icon-152</string>
|
||||
</array>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>-->
|
||||
</dict>
|
||||
</plist>
|
||||
|
116
ios/data/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
@ -0,0 +1,116 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-40.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-60.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-87.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-80.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-121.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-120.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "icon-180.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-20.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-42.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-29.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-58.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-41.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-81.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-77.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-152.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "icon-167.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "icon-main.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-120.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-121.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-152.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-167.png
Normal file
After Width: | Height: | Size: 11 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-180.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-20.png
Normal file
After Width: | Height: | Size: 823 B |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-29.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-40.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-41.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-42.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-58.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-60.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-77.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-80.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-81.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-87.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon-main.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
ios/data/Assets.xcassets/AppIcon.appiconset/icon.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
6
ios/data/Assets.xcassets/Contents.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
BIN
ios/data/icon-120.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
ios/data/icon-152.png
Normal file
After Width: | Height: | Size: 7.1 KiB |
BIN
ios/data/icon-167.png
Normal file
After Width: | Height: | Size: 7.5 KiB |
BIN
ios/data/icon-180.png
Normal file
After Width: | Height: | Size: 7.8 KiB |
BIN
ios/data/icon-20.png
Normal file
After Width: | Height: | Size: 810 B |
BIN
ios/data/icon-29.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
ios/data/icon-40.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
ios/data/icon-58.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
ios/data/icon-60.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
ios/data/icon-76.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
ios/data/icon-80.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
ios/data/icon-87.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
ios/data/icon-main.png
Normal file
After Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.9 KiB |
@ -1,6 +1,6 @@
|
||||
app.version=1.0
|
||||
app.version=3.5
|
||||
app.id=io.anuke.mindustry
|
||||
app.mainclass=io.anuke.mindustry.IOSLauncher
|
||||
app.executable=IOSLauncher
|
||||
app.build=1
|
||||
app.build=11
|
||||
app.name=Mindustry
|
||||
|
@ -1,24 +1,37 @@
|
||||
package io.anuke.mindustry;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.backends.iosrobovm.IOSApplication;
|
||||
import com.badlogic.gdx.backends.iosrobovm.IOSApplicationConfiguration;
|
||||
import com.badlogic.gdx.files.FileHandle;
|
||||
import io.anuke.kryonet.DefaultThreadImpl;
|
||||
import io.anuke.kryonet.KryoClient;
|
||||
import io.anuke.kryonet.KryoServer;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.core.ThreadHandler;
|
||||
import io.anuke.mindustry.io.Platform;
|
||||
import io.anuke.mindustry.io.SaveIO;
|
||||
import io.anuke.mindustry.io.Saves.SaveSlot;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.Bundles;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
import org.robovm.apple.foundation.NSAutoreleasePool;
|
||||
import org.robovm.apple.uikit.UIApplication;
|
||||
import org.robovm.apple.foundation.NSURL;
|
||||
import org.robovm.apple.uikit.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import static io.anuke.mindustry.Vars.control;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
import static org.robovm.apple.foundation.NSPathUtilities.getDocumentsDirectory;
|
||||
|
||||
public class IOSLauncher extends IOSApplication.Delegate {
|
||||
@Override
|
||||
protected IOSApplication createApplication() {
|
||||
@ -27,6 +40,10 @@ public class IOSLauncher extends IOSApplication.Delegate {
|
||||
|
||||
Unit.dp.addition -= 0.2f;
|
||||
|
||||
if(UIDevice.getCurrentDevice().getUserInterfaceIdiom() == UIUserInterfaceIdiom.Pad){
|
||||
Unit.dp.addition = 0.5f;
|
||||
}
|
||||
|
||||
Platform.instance = new Platform() {
|
||||
DateFormat format = SimpleDateFormat.getDateTimeInstance();
|
||||
|
||||
@ -59,12 +76,72 @@ public class IOSLauncher extends IOSApplication.Delegate {
|
||||
public ThreadHandler.ThreadProvider getThreadProvider() {
|
||||
return new DefaultThreadImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void shareFile(FileHandle file){
|
||||
FileHandle to = Gdx.files.absolute(getDocumentsDirectory()).child(file.name());
|
||||
file.copyTo(to);
|
||||
|
||||
NSURL url = new NSURL(to.file());
|
||||
UIActivityViewController p = new UIActivityViewController(Collections.singletonList(url), null);
|
||||
p.getPopoverPresentationController().setSourceView(UIApplication.getSharedApplication().getKeyWindow().getRootViewController().getView());
|
||||
|
||||
UIApplication.getSharedApplication().getKeyWindow().getRootViewController()
|
||||
.presentViewController(p, true, () -> io.anuke.ucore.util.Log.info("Success! Presented {0}", to));
|
||||
}
|
||||
};
|
||||
|
||||
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
|
||||
return new IOSApplication(new Mindustry(), config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean openURL(UIApplication app, NSURL url, UIApplicationOpenURLOptions options) {
|
||||
System.out.println("Opened URL: " + url.getPath());
|
||||
openURL(url);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean didFinishLaunching(UIApplication application, UIApplicationLaunchOptions options) {
|
||||
boolean b = super.didFinishLaunching(application, options);
|
||||
|
||||
if(options != null && options.has(UIApplicationLaunchOptions.Keys.URL())){
|
||||
System.out.println("Opened URL at launch: " + ((NSURL)options.get(UIApplicationLaunchOptions.Keys.URL())).getPath());
|
||||
openURL(((NSURL)options.get(UIApplicationLaunchOptions.Keys.URL())));
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
void openURL(NSURL url){
|
||||
|
||||
Gdx.app.postRunnable(() -> {
|
||||
FileHandle file = Gdx.files.absolute(getDocumentsDirectory()).child(url.getLastPathComponent());
|
||||
Gdx.files.absolute(url.getPath()).copyTo(file);
|
||||
|
||||
if(file.extension().equalsIgnoreCase("mins")){ //open save
|
||||
|
||||
if(SaveIO.isSaveValid(file)){
|
||||
try{
|
||||
SaveSlot slot = control.getSaves().importSave(file);
|
||||
ui.load.runLoadSave(slot);
|
||||
}catch (IOException e){
|
||||
ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e, false)));
|
||||
}
|
||||
}else{
|
||||
ui.showError("$text.save.import.invalid");
|
||||
}
|
||||
|
||||
}else if(file.extension().equalsIgnoreCase("png")){ //open map
|
||||
if(!ui.editor.isShown()){
|
||||
ui.editor.show();
|
||||
}
|
||||
ui.editor.tryLoadMap(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void main(String[] argv) {
|
||||
NSAutoreleasePool pool = new NSAutoreleasePool();
|
||||
UIApplication.main(argv, null, IOSLauncher.class);
|
||||
|
@ -560,6 +560,10 @@ public class ServerControl extends Module {
|
||||
boolean found = false;
|
||||
|
||||
for (Player player : playerGroup.all()) {
|
||||
if(Net.getConnection(player.clientid) == null){
|
||||
err("Player \"{0}\" does not have an associated connection!");
|
||||
continue;
|
||||
}
|
||||
TraceInfo info = netServer.admins.getTrace(Net.getConnection(player.clientid).address);
|
||||
if(info.totalBlocksBroken >= minbreak && info.totalBlocksBroken / Math.max(info.totalBlocksPlaced, 1f) >= ratio){
|
||||
info("&ly - Player '{0}' / UUID &lm{1}&ly found: &lc{2}&ly broken and &lc{3}&ly placed.",
|
||||
|