Merge remote-tracking branch 'fork_master/master'

This commit is contained in:
beito123
2018-12-09 14:26:55 +09:00
35 changed files with 219 additions and 430 deletions

View File

@@ -1,4 +1,4 @@
text.credits.text = Создатель [ROYAL] Anuken. - [SKY]anukendev@gmail.com[][]\n\nЕсть недороботки в переводе?\nПишите в офф. discord-сервер mindustry в канал #русский.\n\nПереводчики на русский язык:\n[YELLOW]Prosta4ok_ua\n[GREEN]xga\n[BLACK]XZimur text.credits.text = Создатель [ROYAL] Anuken. - [SKY]anukendev@gmail.com[][]\n\nЕсть недоработки в переводе?\nПишите в офф. discord-сервер mindustry в канал #русский.\n\nПереводчики на русский язык:\n[YELLOW]Prosta4ok_ua\n[GREEN]xga\n[BLACK]XZimur
text.credits = Авторы text.credits = Авторы
text.contributors = Переводчики и контрибьюторы text.contributors = Переводчики и контрибьюторы
text.discord = Присоединяйтесь к нашему Discord! text.discord = Присоединяйтесь к нашему Discord!
@@ -12,7 +12,7 @@ text.link.wiki.description = Официальная вики Mindustry(англ.
text.linkfail = Не удалось открыть ссылку!\nURL-адрес был скопирован в буфер обмена. text.linkfail = Не удалось открыть ссылку!\nURL-адрес был скопирован в буфер обмена.
text.gameover = Игра окончена text.gameover = Игра окончена
text.gameover.pvp = [accent] {0}[] команда победила! text.gameover.pvp = [accent] {0}[] команда победила!
text.sector.gameover = Этот сектор потерян. Высадится повторно? text.sector.gameover = Этот сектор потерян. Высадиться повторно?
text.sector.retry = Повторить попытку text.sector.retry = Повторить попытку
text.highscore = [YELLOW]Новый рекорд! text.highscore = [YELLOW]Новый рекорд!
text.wave.lasted = Вы продержались до [accent]{0}[]-ой волны. text.wave.lasted = Вы продержались до [accent]{0}[]-ой волны.
@@ -49,9 +49,9 @@ text.mission.main = Главная мисия:[LIGHT_GRAY] {0}
text.mission.info = Информация о миссии text.mission.info = Информация о миссии
text.mission.complete = Миссия выполнена! text.mission.complete = Миссия выполнена!
text.mission.complete.body = Сектор {0},{1} был завоёван. text.mission.complete.body = Сектор {0},{1} был завоёван.
text.mission.wave = Осталось[accent] {0}[] волн из[accent] {1}[]\nВолна через {2} text.mission.wave = Волна[accent] {0}[] из[accent] {1}[]\nВолна через {2}
text.mission.wave.enemies = Осталось[accent] {0}/{1}[] волн:\n{2} враг. text.mission.wave.enemies = Волна[accent] {0} из {1}[]\n{2} враг.
text.mission.wave.enemy = Осталось[accent] {0}/{1}[] волн\n{2} враг text.mission.wave.enemy = Волна[accent] {0} из {1}[]\n{2} враг
text.mission.wave.menu = Пережить[accent] {0} []волн text.mission.wave.menu = Пережить[accent] {0} []волн
text.mission.battle = Уничтожьте ядро противника. text.mission.battle = Уничтожьте ядро противника.
text.mission.resource.menu = Добыть {0} х{1} text.mission.resource.menu = Добыть {0} х{1}
@@ -266,7 +266,7 @@ text.error.invalidaddress = Некорректный адрес.
text.error.timedout = Время ожидания истекло!\nУбедитесь, что хост настроен для перенаправления портов и адрес корректный! text.error.timedout = Время ожидания истекло!\nУбедитесь, что хост настроен для перенаправления портов и адрес корректный!
text.error.mismatch = Ошибка пакета:\nвозможное несоответствие версии клиента/сервера. \nУбедитесь, что у Вас и у владельца сервера установлена последняя версия Mindustry! text.error.mismatch = Ошибка пакета:\nвозможное несоответствие версии клиента/сервера. \nУбедитесь, что у Вас и у владельца сервера установлена последняя версия Mindustry!
text.error.alreadyconnected = Вы уже подключены. text.error.alreadyconnected = Вы уже подключены.
text.error.mapnotfound = Map file not found! text.error.mapnotfound = Не найден файл карты!
text.error.any = Неизвестная сетевая ошибка. text.error.any = Неизвестная сетевая ошибка.
text.settings.language = Язык text.settings.language = Язык
text.settings.reset = Сбросить по умолчанию text.settings.reset = Сбросить по умолчанию
@@ -345,7 +345,7 @@ text.category.power = Энергия
text.category.liquids = Жидкости text.category.liquids = Жидкости
text.category.items = Предметы text.category.items = Предметы
text.category.crafting = Создание text.category.crafting = Создание
text.category.shooting = Cтрельба text.category.shooting = Стрельба
text.category.optional = Дополнительные улучшения text.category.optional = Дополнительные улучшения
setting.autotarget.name = Авто-цель setting.autotarget.name = Авто-цель
setting.fpscap.name = Макс. FPS setting.fpscap.name = Макс. FPS
@@ -407,8 +407,8 @@ mode.waves.name = Волны
mode.waves.description = Обычный режим. В режиме "Волны" надо самим добывать ресурсы и сами волны идут безостановочно. mode.waves.description = Обычный режим. В режиме "Волны" надо самим добывать ресурсы и сами волны идут безостановочно.
mode.sandbox.name = Песочница mode.sandbox.name = Песочница
mode.sandbox.description = Бесконечные ресурсы и нет таймера для волн, но можно самим вызвать волну. mode.sandbox.description = Бесконечные ресурсы и нет таймера для волн, но можно самим вызвать волну.
mode.freebuild.name = Cвободная\nстрой mode.freebuild.name = Свободная\nстройка
mode.freebuild.description = ограниченные ресурсы и нет таймера для волн. mode.freebuild.description = Ограниченные ресурсы и нет таймера для волн.
mode.pvp.name = Противо-\nстояние mode.pvp.name = Противо-\nстояние
mode.pvp.description = боритесь против других игроков. mode.pvp.description = боритесь против других игроков.
content.item.name = Предметы content.item.name = Предметы
@@ -435,7 +435,7 @@ item.silicon.description = Очень полезный полупроводни
item.plastanium.name = Пластиний item.plastanium.name = Пластиний
item.plastanium.description = Легкий, пластичный материал, используемый в современных самолетах и боеприпасах для фрагментации. item.plastanium.description = Легкий, пластичный материал, используемый в современных самолетах и боеприпасах для фрагментации.
item.phase-fabric.name = Фазовая ткань item.phase-fabric.name = Фазовая ткань
item.phase-fabric.description = Невесомое вещество, используемое в современной электронике и технологии самовосстановления. item.phase-fabric.description = Невесомое вещество, используемое в современной электронике и технологии самовосстановления. Непригодна для вышивания.
item.surge-alloy.name = Высокопрочный сплав item.surge-alloy.name = Высокопрочный сплав
item.surge-alloy.description = Передовой сплав с уникальными электрическими свойствами. item.surge-alloy.description = Передовой сплав с уникальными электрическими свойствами.
item.biomatter.name = Биоматерия item.biomatter.name = Биоматерия
@@ -461,7 +461,7 @@ mech.delta-mech.description = Быстрый, легкобронированны
mech.tau-mech.name = Тау mech.tau-mech.name = Тау
mech.tau-mech.weapon = Восстановительный лазер mech.tau-mech.weapon = Восстановительный лазер
mech.tau-mech.ability = Регенирирующая вспышка mech.tau-mech.ability = Регенирирующая вспышка
mech.tau-mech.description = Мех поддержки. Исцеляет союзные блоки, стреляя в них. Может исцелить союзников радиусом с его способностью восстанавления. mech.tau-mech.description = Мех поддержки. Чинит союзные блоки, стреляя в них. Может исцелить союзников радиусом с его способностью восстанавления.
mech.omega-mech.name = Омега mech.omega-mech.name = Омега
mech.omega-mech.weapon = Ракетомётный пулемётконфигурация mech.omega-mech.weapon = Ракетомётный пулемётконфигурация
mech.omega-mech.ability = Защитная mech.omega-mech.ability = Защитная
@@ -498,7 +498,7 @@ block.constructing = {0}[LIGHT_GRAY](В процессе)
block.spawn.name = Точка появления врагов block.spawn.name = Точка появления врагов
block.core.name = Ядро block.core.name = Ядро
block.space.name = Пустота block.space.name = Пустота
block.metalfloor.name = Мeталичeский пoл block.metalfloor.name = Металлическая плита
block.deepwater.name = Глубоководье block.deepwater.name = Глубоководье
block.water.name = Вода block.water.name = Вода
block.lava.name = Лава block.lava.name = Лава
@@ -731,8 +731,8 @@ block.solar-panel-large.description = Зелёная энергия. Больш
block.thorium-reactor.description = Производит энергию в большом количестве. Может взорваться. Требуется торий и жидкость для охлаждения (вода или криогенная). block.thorium-reactor.description = Производит энергию в большом количестве. Может взорваться. Требуется торий и жидкость для охлаждения (вода или криогенная).
block.rtg-generator.description = Радиоизотопный термоэлектрический генератор, который не требует охлаждения, но обеспечивает меньшую мощность, чем ториевый реактор. block.rtg-generator.description = Радиоизотопный термоэлектрический генератор, который не требует охлаждения, но обеспечивает меньшую мощность, чем ториевый реактор.
block.unloader.description = Выгружает из ядра или хранилища верхний левый предмет. block.unloader.description = Выгружает из ядра или хранилища верхний левый предмет.
block.container.description = Хранит небольшое количество предметов(250). Используйте его для создания буферов, когда существует непостоянная потребность в материалах. [LIGHT_GRAY] Разгрузчик[] можно использовать для извлечения элементов из хранилища. block.container.description = Хранит небольшое количество предметов(200). Используйте его для создания буферов, когда существует непостоянная потребность в материалах. [LIGHT_GRAY] Разгрузчик[] можно использовать для извлечения элементов из хранилища.
block.vault.description = Хранит большое количество предметов(1000). Используйте его для создания буферов, когда существует непостоянная потребность в материалах.[LIGHT_GRAY] Разгрузчик[] можно использовать для извлечения элементов из хранилища. block.vault.description = Хранит большое количество предметов(900). Используйте его для создания буферов, когда существует непостоянная потребность в материалах.[LIGHT_GRAY] Разгрузчик[] можно использовать для извлечения элементов из хранилища.
block.mechanical-drill.description = Самый первый доступный бур. \n\nДобывает медь, свинец, уголь, песок. \n\nМожно подвести к нему [BLUE] воду[] для увеличения скорости сверления. block.mechanical-drill.description = Самый первый доступный бур. \n\nДобывает медь, свинец, уголь, песок. \n\nМожно подвести к нему [BLUE] воду[] для увеличения скорости сверления.
block.pneumatic-drill.description = Улучшенная версия механического бура.\n\nДобывает тоже самое, что и механический бур. Также может добывать титан и камень.\n\nМожно подвести к нему[BLUE] воду[] для увеличения скорости сверления. block.pneumatic-drill.description = Улучшенная версия механического бура.\n\nДобывает тоже самое, что и механический бур. Также может добывать титан и камень.\n\nМожно подвести к нему[BLUE] воду[] для увеличения скорости сверления.
block.laser-drill.description = Улучшенная версия пневматического бура.\n\nДобывает тоже самое, что и пневматический бур. Также может добывать торий.\n\nМожно подвести к нему[BLUE] воду[] для увеличения скорости сверления. block.laser-drill.description = Улучшенная версия пневматического бура.\n\nДобывает тоже самое, что и пневматический бур. Также может добывать торий.\n\nМожно подвести к нему[BLUE] воду[] для увеличения скорости сверления.

View File

@@ -83,7 +83,7 @@ public class Items implements ContentList{
}}; }};
biomatter = new Item("biomatter", Color.valueOf("648b55")){{ biomatter = new Item("biomatter", Color.valueOf("648b55")){{
flammability = 0.4f; flammability = 0.55f;
fluxiness = 0.3f; fluxiness = 0.3f;
}}; }};

View File

@@ -26,7 +26,7 @@ public class Liquids implements ContentList{
lava = new Liquid("lava", Color.valueOf("e37341")){ lava = new Liquid("lava", Color.valueOf("e37341")){
{ {
temperature = 0.8f; temperature = 1f;
viscosity = 0.8f; viscosity = 0.8f;
tier = 2; tier = 2;
effect = StatusEffects.melting; effect = StatusEffects.melting;

View File

@@ -123,6 +123,7 @@ public class Mechs implements ContentList{
speed = 0.44f; speed = 0.44f;
drag = 0.35f; drag = 0.35f;
boostSpeed = 0.8f; boostSpeed = 0.8f;
canHeal = true;
weapon = Weapons.healBlaster; weapon = Weapons.healBlaster;
armor = 15f; armor = 15f;
trailColorTo = Palette.heal; trailColorTo = Palette.heal;
@@ -287,8 +288,8 @@ public class Mechs implements ContentList{
trident = new Mech("trident-ship", true){ trident = new Mech("trident-ship", true){
{ {
drillPower = 2; drillPower = 2;
speed = 0.12f; speed = 0.14f;
drag = 0.035f; drag = 0.034f;
mass = 2.5f; mass = 2.5f;
turnCursor = false; turnCursor = false;
armor = 20f; armor = 20f;

View File

@@ -42,15 +42,21 @@ public class Recipes implements ContentList{
new Recipe(defense, DefenseBlocks.surgeWall, new ItemStack(Items.surgealloy, 12)); new Recipe(defense, DefenseBlocks.surgeWall, new ItemStack(Items.surgealloy, 12));
new Recipe(defense, DefenseBlocks.surgeWallLarge, new ItemStack(Items.surgealloy, 12 * 4)); new Recipe(defense, DefenseBlocks.surgeWallLarge, new ItemStack(Items.surgealloy, 12 * 4));
new Recipe(effect, StorageBlocks.container, new ItemStack(Items.densealloy, 200));
new Recipe(effect, StorageBlocks.vault, new ItemStack(Items.densealloy, 500), new ItemStack(Items.thorium, 250));
//core disabled due to being broken
new Recipe(effect, StorageBlocks.core,
new ItemStack(Items.copper, 2000), new ItemStack(Items.densealloy, 1500),
new ItemStack(Items.silicon, 1500), new ItemStack(Items.thorium, 500),
new ItemStack(Items.surgealloy, 500), new ItemStack(Items.phasefabric, 750)
);
//projectors //projectors
new Recipe(effect, DefenseBlocks.mendProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.densealloy, 150), new ItemStack(Items.titanium, 50), new ItemStack(Items.silicon, 180)); new Recipe(effect, DefenseBlocks.mendProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.densealloy, 150), new ItemStack(Items.titanium, 50), new ItemStack(Items.silicon, 180));
new Recipe(effect, DefenseBlocks.overdriveProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.densealloy, 150), new ItemStack(Items.titanium, 150), new ItemStack(Items.silicon, 250)); new Recipe(effect, DefenseBlocks.overdriveProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.densealloy, 150), new ItemStack(Items.titanium, 150), new ItemStack(Items.silicon, 250));
new Recipe(effect, DefenseBlocks.forceProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.densealloy, 150), new ItemStack(Items.titanium, 150), new ItemStack(Items.silicon, 250)); new Recipe(effect, DefenseBlocks.forceProjector, new ItemStack(Items.lead, 200), new ItemStack(Items.densealloy, 150), new ItemStack(Items.titanium, 150), new ItemStack(Items.silicon, 250));
new Recipe(effect, StorageBlocks.unloader, new ItemStack(Items.densealloy, 50), new ItemStack(Items.silicon, 60));
new Recipe(effect, StorageBlocks.container, new ItemStack(Items.densealloy, 200));
new Recipe(effect, StorageBlocks.vault, new ItemStack(Items.densealloy, 500), new ItemStack(Items.thorium, 250));
new Recipe(effect, DefenseBlocks.shockMine, new ItemStack(Items.lead, 50), new ItemStack(Items.silicon, 25)) new Recipe(effect, DefenseBlocks.shockMine, new ItemStack(Items.lead, 50), new ItemStack(Items.silicon, 25))
.setDependencies(Items.blastCompound); .setDependencies(Items.blastCompound);
@@ -82,6 +88,7 @@ public class Recipes implements ContentList{
new Recipe(distribution, DistributionBlocks.sorter, new ItemStack(Items.densealloy, 4), new ItemStack(Items.copper, 4)); new Recipe(distribution, DistributionBlocks.sorter, new ItemStack(Items.densealloy, 4), new ItemStack(Items.copper, 4));
new Recipe(distribution, DistributionBlocks.overflowGate, new ItemStack(Items.densealloy, 4), new ItemStack(Items.copper, 8)); new Recipe(distribution, DistributionBlocks.overflowGate, new ItemStack(Items.densealloy, 4), new ItemStack(Items.copper, 8));
new Recipe(distribution, DistributionBlocks.itemBridge, new ItemStack(Items.densealloy, 8), new ItemStack(Items.copper, 8)); new Recipe(distribution, DistributionBlocks.itemBridge, new ItemStack(Items.densealloy, 8), new ItemStack(Items.copper, 8));
new Recipe(distribution, StorageBlocks.unloader, new ItemStack(Items.densealloy, 50), new ItemStack(Items.silicon, 60));
new Recipe(distribution, DistributionBlocks.massDriver, new ItemStack(Items.densealloy, 250), new ItemStack(Items.silicon, 150), new ItemStack(Items.lead, 250), new ItemStack(Items.thorium, 100)); new Recipe(distribution, DistributionBlocks.massDriver, new ItemStack(Items.densealloy, 250), new ItemStack(Items.silicon, 150), new ItemStack(Items.lead, 250), new ItemStack(Items.thorium, 100));
//CRAFTING //CRAFTING
@@ -134,13 +141,6 @@ public class Recipes implements ContentList{
new Recipe(power, PowerBlocks.thoriumReactor, new ItemStack(Items.lead, 600), new ItemStack(Items.silicon, 400), new ItemStack(Items.densealloy, 300), new ItemStack(Items.thorium, 300)); new Recipe(power, PowerBlocks.thoriumReactor, new ItemStack(Items.lead, 600), new ItemStack(Items.silicon, 400), new ItemStack(Items.densealloy, 300), new ItemStack(Items.thorium, 300));
new Recipe(power, PowerBlocks.rtgGenerator, new ItemStack(Items.lead, 200), new ItemStack(Items.silicon, 150), new ItemStack(Items.phasefabric, 50), new ItemStack(Items.plastanium, 150), new ItemStack(Items.thorium, 100)); new Recipe(power, PowerBlocks.rtgGenerator, new ItemStack(Items.lead, 200), new ItemStack(Items.silicon, 150), new ItemStack(Items.phasefabric, 50), new ItemStack(Items.plastanium, 150), new ItemStack(Items.thorium, 100));
//core disabled due to being broken
/*new Recipe(distribution, StorageBlocks.core,
new ItemStack(Items.copper, 2000), new ItemStack(Items.densealloy, 1500),
new ItemStack(Items.silicon, 1500), new ItemStack(Items.thorium, 500),
new ItemStack(Items.surgealloy, 500), new ItemStack(Items.phasefabric, 750)
);*/
//DRILLS, PRODUCERS //DRILLS, PRODUCERS
new Recipe(production, ProductionBlocks.mechanicalDrill, new ItemStack(Items.copper, 45)).setAlwaysUnlocked(true); new Recipe(production, ProductionBlocks.mechanicalDrill, new ItemStack(Items.copper, 45)).setAlwaysUnlocked(true);
new Recipe(production, ProductionBlocks.pneumaticDrill, new ItemStack(Items.copper, 60), new ItemStack(Items.densealloy, 50)); new Recipe(production, ProductionBlocks.pneumaticDrill, new ItemStack(Items.copper, 60), new ItemStack(Items.densealloy, 50));

View File

@@ -152,7 +152,7 @@ public class Weapons implements ContentList{
bomberTrident = new Weapon("bomber"){{ bomberTrident = new Weapon("bomber"){{
length = 0f; length = 0f;
width = 2f; width = 2f;
reload = 9f; reload = 8f;
shots = 2; shots = 2;
roundrobin = true; roundrobin = true;
ejectEffect = Fx.none; ejectEffect = Fx.none;

View File

@@ -196,9 +196,9 @@ public class CraftingBlocks extends BlockList implements ContentList{
biomatterCompressor = new Compressor("biomattercompressor"){{ biomatterCompressor = new Compressor("biomattercompressor"){{
liquidCapacity = 60f; liquidCapacity = 60f;
itemCapacity = 50; itemCapacity = 50;
craftTime = 25f; craftTime = 20f;
outputLiquid = Liquids.oil; outputLiquid = Liquids.oil;
outputLiquidAmount = 1.5f; outputLiquidAmount = 2.5f;
size = 2; size = 2;
health = 320; health = 320;
hasLiquids = true; hasLiquids = true;

View File

@@ -50,10 +50,10 @@ public class LiquidBlocks extends BlockList implements ContentList{
}}; }};
liquidRouter = new LiquidRouter("liquid-router"){{ liquidRouter = new LiquidRouter("liquid-router"){{
liquidCapacity = 40f; liquidCapacity = 20f;
}}; }};
liquidtank = new LiquidRouter("liquid-tank"){{ liquidtank = new LiquidTank("liquid-tank"){{
size = 3; size = 3;
liquidCapacity = 1500f; liquidCapacity = 1500f;
health = 500; health = 500;

View File

@@ -21,7 +21,7 @@ public class PowerBlocks extends BlockList implements ContentList{
thermalGenerator = new LiquidHeatGenerator("thermal-generator"){{ thermalGenerator = new LiquidHeatGenerator("thermal-generator"){{
maxLiquidGenerate = 2f; maxLiquidGenerate = 2f;
powerCapacity = 40f; powerCapacity = 40f;
powerPerLiquid = 0.3f; powerPerLiquid = 0.35f;
generateEffect = BlockFx.redgeneratespark; generateEffect = BlockFx.redgeneratespark;
size = 2; size = 2;
}}; }};

View File

@@ -99,13 +99,13 @@ public class ProductionBlocks extends BlockList implements ContentList{
cultivator = new Cultivator("cultivator"){{ cultivator = new Cultivator("cultivator"){{
result = Items.biomatter; result = Items.biomatter;
drillTime = 260; drillTime = 200;
size = 2; size = 2;
hasLiquids = true; hasLiquids = true;
hasPower = true; hasPower = true;
consumes.power(0.08f); consumes.power(0.08f);
consumes.liquid(Liquids.water, 0.2f); consumes.liquid(Liquids.water, 0.15f);
}}; }};
} }

View File

@@ -13,20 +13,21 @@ public class StorageBlocks extends BlockList implements ContentList{
public void load(){ public void load(){
core = new CoreBlock("core"){{ core = new CoreBlock("core"){{
health = 1100; health = 1100;
itemCapacity = 3000;
}}; }};
vault = new Vault("vault"){{ vault = new Vault("vault"){{
size = 3; size = 3;
itemCapacity = 900; itemCapacity = 1000;
}}; }};
container = new Vault("container"){{ container = new Vault("container"){{
size = 2; size = 2;
itemCapacity = 200; itemCapacity = 300;
}}; }};
unloader = new SortedUnloader("unloader"){{ unloader = new SortedUnloader("unloader"){{
speed = 12f; speed = 7f;
}}; }};
} }
} }

View File

@@ -69,7 +69,7 @@ public class TurretBlocks extends BlockList implements ContentList{
inaccuracy = 5f; inaccuracy = 5f;
shootCone = 50f; shootCone = 50f;
shootEffect = ShootFx.shootLiquid; shootEffect = ShootFx.shootLiquid;
range = 70f; range = 90f;
health = 360; health = 360;
drawer = (tile, entity) -> { drawer = (tile, entity) -> {

View File

@@ -334,7 +334,7 @@ public class TurretBullets extends BulletList implements ContentList{
lifetime = 200f; lifetime = 200f;
despawneffect = BlockFx.smeltsmoke; despawneffect = BlockFx.smeltsmoke;
hiteffect = BulletFx.hitBulletBig; hiteffect = BulletFx.hitBulletBig;
drag = 0.01f; drag = 0.005f;
} }
@Override @Override

View File

@@ -375,7 +375,7 @@ public class Control extends Module{
} }
} }
if(Inputs.keyTap("screenshot") && !ui.chatfrag.chatOpen()){ if(!mobile && Inputs.keyTap("screenshot") && !ui.chatfrag.chatOpen()){
renderer.takeMapScreenshot(); renderer.takeMapScreenshot();
} }

View File

@@ -645,7 +645,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
} }
protected void updateFlying(){ protected void updateFlying(){
if(Units.invalidateTarget(target, this)){ if(Units.invalidateTarget(target, this) && !(target instanceof TileEntity && ((TileEntity) target).damaged() && target.getTeam() == team &&
mech.canHeal && distanceTo(target) < getWeapon().getAmmo().getRange())){
target = null; target = null;
} }
@@ -726,11 +727,22 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
isShooting = false; isShooting = false;
if(Settings.getBool("autotarget")){ if(Settings.getBool("autotarget")){
target = Units.getClosestTarget(team, x, y, getWeapon().getAmmo().getRange()); target = Units.getClosestTarget(team, x, y, getWeapon().getAmmo().getRange());
if(mech.canHeal && target == null){
target = Geometry.findClosest(x, y, world.indexer.getDamaged(Team.blue));
if(target != null && distanceTo(target) > getWeapon().getAmmo().getRange()){
target = null;
}else if(target != null){
target = ((Tile)target).entity;
}
}
if(target != null){ if(target != null){
setMineTile(null); setMineTile(null);
} }
} }
}else if(target.isValid()){ }else if(target.isValid() || (target instanceof TileEntity && ((TileEntity) target).damaged() && target.getTeam() == team &&
mech.canHeal && distanceTo(target) < getWeapon().getAmmo().getRange())){
//rotate toward and shoot the target //rotate toward and shoot the target
if(mech.turnCursor){ if(mech.turnCursor){
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f); rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f);

View File

@@ -13,7 +13,6 @@ public enum GameMode{
}}, }},
attack{{ attack{{
disableWaves = true; disableWaves = true;
hidden = true;
enemyCheat = true; enemyCheat = true;
}}, }},
victory{{ victory{{

View File

@@ -165,14 +165,7 @@ public class Saves{
public void save(){ public void save(){
long time = totalPlaytime; long time = totalPlaytime;
threads.runGraphics(() -> {
//Renderer fog needs to be written on graphics thread, but save() can run on logic thread
//thus, runGraphics is required here
renderer.fog.writeFog(); renderer.fog.writeFog();
//save on the logic thread
threads.run(() -> {
long prev = totalPlaytime; long prev = totalPlaytime;
totalPlaytime = time; totalPlaytime = time;
@@ -183,8 +176,6 @@ public class Saves{
} }
totalPlaytime = prev; totalPlaytime = prev;
});
});
} }
public boolean isHidden(){ public boolean isHidden(){

View File

@@ -203,7 +203,7 @@ public class OverlayRenderer{
if(finion > 0.9f) finion = 1f; //fixes precision errors if(finion > 0.9f) finion = 1f; //fixes precision errors
finion = Mathf.clamp(finion); finion = Mathf.clamp(finion);
if(finion > 0) finion = Mathf.clamp(finion, 0.24f, 1f); if(finion > 0.001f) finion = Mathf.clamp(finion, 0.24f, 1f);
float len = 3; float len = 3;

View File

@@ -96,6 +96,9 @@ public class MobileInput extends InputHandler implements GestureListener{
TileEntity entity = tile.entity; TileEntity entity = tile.entity;
player.setMineTile(null); player.setMineTile(null);
player.target = entity; player.target = entity;
}else if(tile != null && player.mech.canHeal && tile.entity != null && tile.getTeam() == player.getTeam() && tile.entity.damaged()){
player.setMineTile(null);
player.target = tile.entity;
} }
} }
} }
@@ -221,11 +224,6 @@ public class MobileInput extends InputHandler implements GestureListener{
} }
}).update(l -> l.setChecked(mode == breaking)); }).update(l -> l.setChecked(mode == breaking));
//rotate button
table.addImageButton("icon-arrow", "clear-partial", 16 * 2f, () -> rotation = Mathf.mod(rotation + 1, 4))
.update(i -> i.getImage().setRotationOrigin(rotation * 90, Align.center))
.visible(() -> recipe != null && recipe.result.rotate);
//cancel button //cancel button
table.addImageButton("icon-cancel", "clear-partial", 16 * 2f, () -> { table.addImageButton("icon-cancel", "clear-partial", 16 * 2f, () -> {
player.clearBuilding(); player.clearBuilding();
@@ -233,6 +231,11 @@ public class MobileInput extends InputHandler implements GestureListener{
recipe = null; recipe = null;
}).visible(() -> player.isBuilding() || recipe != null || mode == breaking); }).visible(() -> player.isBuilding() || recipe != null || mode == breaking);
//rotate button
table.addImageButton("icon-arrow", "clear-partial", 16 * 2f, () -> rotation = Mathf.mod(rotation + 1, 4))
.update(i -> i.getImage().setRotationOrigin(rotation * 90, Align.center))
.visible(() -> recipe != null && recipe.result.rotate);
//confirm button //confirm button
table.addImageButton("icon-check", "clear-partial", 16 * 2f, () -> { table.addImageButton("icon-check", "clear-partial", 16 * 2f, () -> {
for(PlaceRequest request : selection){ for(PlaceRequest request : selection){

View File

@@ -34,6 +34,7 @@ public class Mech extends UnlockableContent{
public Color trailColorTo = Palette.boostTo; public Color trailColorTo = Palette.boostTo;
public int itemCapacity = 30; public int itemCapacity = 30;
public boolean turnCursor = true; public boolean turnCursor = true;
public boolean canHeal = false;
public float weaponOffsetX, weaponOffsetY; public float weaponOffsetX, weaponOffsetY;
public Weapon weapon = Weapons.blaster; public Weapon weapon = Weapons.blaster;

View File

@@ -0,0 +1,8 @@
package io.anuke.mindustry.world.blocks.distribution;
public class LiquidTank extends LiquidRouter{
public LiquidTank(String name){
super(name);
}
}

View File

@@ -14,7 +14,7 @@ public class LiquidHeatGenerator extends LiquidGenerator{
public void setStats(){ public void setStats(){
super.setStats(); super.setStats();
stats.add(BlockStat.basePowerGeneration, maxLiquidGenerate * powerPerLiquid * 60f, StatUnit.powerSecond); stats.add(BlockStat.basePowerGeneration, maxLiquidGenerate * powerPerLiquid * 60f * 0.5f, StatUnit.powerSecond);
} }
@Override @Override

View File

@@ -47,7 +47,8 @@ public class PowerNode extends PowerBlock{
@Remote(targets = Loc.both, called = Loc.server, forward = true) @Remote(targets = Loc.both, called = Loc.server, forward = true)
public static void linkPowerNodes(Player player, Tile tile, Tile other){ public static void linkPowerNodes(Player player, Tile tile, Tile other){
if(tile.entity.power == null || !((PowerNode)tile.block()).linkValid(tile, other)) return; if(tile.entity.power == null || !((PowerNode)tile.block()).linkValid(tile, other)
|| tile.entity.power.links.size >= ((PowerNode)tile.block()).maxNodes) return;
TileEntity entity = tile.entity(); TileEntity entity = tile.entity();

View File

@@ -51,7 +51,6 @@ public class CoreBlock extends StorageBlock{
update = true; update = true;
size = 3; size = 3;
hasItems = true; hasItems = true;
itemCapacity = 2000;
viewRange = 200f; viewRange = 200f;
flags = EnumSet.of(BlockFlag.resupplyPoint, BlockFlag.target); flags = EnumSet.of(BlockFlag.resupplyPoint, BlockFlag.target);
} }
@@ -83,8 +82,18 @@ public class CoreBlock extends StorageBlock{
if(entity != null) entity.solid = solid; if(entity != null) entity.solid = solid;
} }
@Override
public int getMaximumAccepted(Tile tile, Item item){
return itemCapacity * state.teams.get(tile.getTeam()).cores.size;
}
@Override @Override
public void onProximityUpdate(Tile tile) { public void onProximityUpdate(Tile tile) {
for(Tile other : state.teams.get(tile.getTeam()).cores){
if(other != tile){
tile.entity.items = other.entity.items;
}
}
state.teams.get(tile.getTeam()).cores.add(tile); state.teams.get(tile.getTeam()).cores.add(tile);
} }
@@ -96,6 +105,11 @@ public class CoreBlock extends StorageBlock{
@Override @Override
public void removed(Tile tile){ public void removed(Tile tile){
state.teams.get(tile.getTeam()).cores.remove(tile); state.teams.get(tile.getTeam()).cores.remove(tile);
int max = itemCapacity * state.teams.get(tile.getTeam()).cores.size;
for(Item item : content.items()){
tile.entity.items.set(item, Math.min(tile.entity.items.get(item), max));
}
} }
@Override @Override
@@ -222,7 +236,7 @@ public class CoreBlock extends StorageBlock{
return new CoreEntity(); return new CoreEntity();
} }
public class CoreEntity extends StorageEntity implements SpawnerTrait{ public class CoreEntity extends TileEntity implements SpawnerTrait{
public Unit currentUnit; public Unit currentUnit;
int droneID = -1; int droneID = -1;
boolean solid = true; boolean solid = true;

View File

@@ -7,6 +7,7 @@ import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.SelectionTrait; import io.anuke.mindustry.world.blocks.SelectionTrait;
import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Draw;
@@ -19,15 +20,30 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.content; import static io.anuke.mindustry.Vars.content;
import static io.anuke.mindustry.Vars.threads; import static io.anuke.mindustry.Vars.threads;
public class SortedUnloader extends Unloader implements SelectionTrait{ public class SortedUnloader extends Block implements SelectionTrait{
protected float speed = 1f; protected float speed = 1f;
protected final int timerUnload = timers++;
private static Item lastItem; private static Item lastItem;
public SortedUnloader(String name){ public SortedUnloader(String name){
super(name); super(name);
update = true;
solid = true;
health = 70;
hasItems = true;
configurable = true; configurable = true;
} }
@Override
public boolean canDump(Tile tile, Tile to, Item item){
Block block = to.target().block();
return !(block instanceof StorageBlock);
}
@Override
public void setBars(){}
@Override @Override
public void playerPlaced(Tile tile){ public void playerPlaced(Tile tile){
threads.runDelay(() -> Call.setSortedUnloaderItem(null, tile, lastItem)); threads.runDelay(() -> Call.setSortedUnloaderItem(null, tile, lastItem));

View File

@@ -1,20 +1,10 @@
package io.anuke.mindustry.world.blocks.storage; package io.anuke.mindustry.world.blocks.storage;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Shaders;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.BarType; import io.anuke.mindustry.world.BarType;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import static io.anuke.mindustry.Vars.tilesize;
public abstract class StorageBlock extends Block{ public abstract class StorageBlock extends Block{
@@ -23,6 +13,16 @@ public abstract class StorageBlock extends Block{
hasItems = true; hasItems = true;
} }
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
return tile.entity.items.get(item) < getMaximumAccepted(tile, item);
}
@Override
public int getMaximumAccepted(Tile tile, Item item){
return itemCapacity;
}
@Override @Override
public void setBars(){ public void setBars(){
super.setBars(); super.setBars();
@@ -34,85 +34,6 @@ public abstract class StorageBlock extends Block{
return false; return false;
} }
@Override
public void onProximityAdded(Tile tile){
StorageEntity entity = tile.entity();
entity.graph.set(tile);
for(Tile prox : tile.entity.proximity()){
if(prox.block() instanceof StorageBlock){
StorageEntity other = prox.entity();
entity.graph.merge(other.graph);
}
}
}
@Override
public void onProximityRemoved(Tile tile){
StorageEntity entity = tile.entity();
entity.graph.remove(tile);
}
@Override
public void drawSelect(Tile tile){
StorageEntity entity = tile.entity();
if(entity.graph.getTiles().size > 1){
Shaders.outline.color.set(Palette.accent);
Graphics.beginShaders(Shaders.outline);
for(Tile other : entity.graph.getTiles()){
Fill.square(other.drawx(), other.drawy(), other.block().size * tilesize);
}
Draw.color(Color.CLEAR);
Graphics.endShaders();
Draw.color();
}
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
StorageEntity entity = tile.entity();
return entity.graph.accept(item);
}
@Override
public int acceptStack(Item item, int amount, Tile tile, Unit source){
StorageEntity entity = tile.entity();
if(acceptItem(item, tile, tile) && hasItems && (source == null || source.getTeam() == tile.getTeam())){
return Math.min(entity.graph.accept(item, amount), amount);
}else{
return 0;
}
}
@Override
public float inventoryScaling(Tile tile){
StorageEntity entity = tile.entity();
return 1f / entity.graph.getTiles().size;
}
@Override
public TileEntity newEntity(){
return new StorageEntity();
}
@Override
public Array<Object> getDebugInfo(Tile tile){
Array<Object> arr = super.getDebugInfo(tile);
StorageEntity entity = tile.entity();
arr.addAll("storage graph", entity.graph.getID(),
"graph capacity", entity.graph.getCapacity(),
"graph tiles", entity.graph.getTiles().size,
"graph item ID", entity.graph.items().getID());
return arr;
}
/** /**
* Removes an item and returns it. If item is not null, it should return the item. * Removes an item and returns it. If item is not null, it should return the item.
* Returns null if no items are there. * Returns null if no items are there.
@@ -144,8 +65,4 @@ public abstract class StorageBlock extends Block{
return entity.items.has(item); return entity.items.has(item);
} }
} }
public class StorageEntity extends TileEntity{
public StorageGraph graph = new StorageGraph();
}
} }

View File

@@ -1,151 +0,0 @@
package io.anuke.mindustry.world.blocks.storage;
import com.badlogic.gdx.utils.IntSet;
import com.badlogic.gdx.utils.ObjectSet;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.storage.StorageBlock.StorageEntity;
import io.anuke.mindustry.world.modules.ItemModule;
public class StorageGraph{
private static IntSet closedSet = new IntSet();
private static Queue<Tile> queue = new Queue<>();
private static ObjectSet<ItemModule> itemSet = new ObjectSet<>();
private static int lastID;
private final int id = lastID++;
private ObjectSet<Tile> tiles = new ObjectSet<>();
private ItemModule items = new ItemModule();
private int capacity;
public void set(Tile tile){
items.addAll(tile.entity.items);
items.setID(tile.entity.items.getID());
add(tile);
}
public void add(Tile tile){
if(!tiles.add(tile)) return;
StorageEntity e = tile.entity();
e.graph = this;
capacity += tile.block().itemCapacity;
if(tile.entity.items != null && tile.entity.items.getID() != items.getID()){
items.addAll(tile.entity.items);
}
tile.entity.items = items;
}
public void remove(Tile tile){
if(!tiles.contains(tile)) return;
for(Tile other : tiles){
if(other == tile) continue;
StorageEntity entity = other.entity();
entity.graph = null;
entity.items = new ItemModule();
float fraction = (float)other.block().itemCapacity / capacity;
items.forEach((item, amount) -> {
int added = (int)(fraction * amount);
entity.items.add(item, added);
items.remove(item, added);
});
}
//handle remaining items that didn't get added
Item taken;
while((taken = items.take()) != null){
for(Tile other : tiles){
if(other == tile) continue;
//insert item into first found block
if(other.entity.items.get(taken) < other.block().itemCapacity){
other.entity.items.add(taken, 1);
break;
}
}
}
items.clear();
capacity = 0;
for(Tile other : tile.entity.proximity()){
if(other.block() instanceof StorageBlock && other.<StorageEntity>entity().graph == null){
StorageGraph graph = new StorageGraph();
other.<StorageEntity>entity().graph = graph;
graph.reflow(tile, other);
}
}
}
public void reflow(Tile base, Tile tile){
queue.clear();
queue.addLast(tile);
closedSet.clear();
itemSet.clear();
while(queue.size > 0){
Tile child = queue.removeFirst();
StorageEntity entity = child.entity();
entity.graph = this;
if(!itemSet.add(child.entity.items)) child.entity.items = null;
add(child);
for(Tile next : child.entity.proximity()){
if(next != base && next.block() instanceof StorageBlock && next.<StorageEntity>entity().graph == null && !closedSet.contains(next.pos())){
queue.addLast(next);
closedSet.add(next.pos());
}
}
}
}
public void merge(StorageGraph other){
if(this == other || other == null) return;
itemSet.clear();
for(Tile tile : other.tiles){
if(!itemSet.add(tile.entity.items)){
tile.entity.items = null;
}
}
for(Tile tile : other.tiles){
add(tile);
}
}
public boolean accept(Item item){
return accept(item, 1) == 1;
}
public int accept(Item item, int amount){
return Math.min(capacity - items.get(item), amount);
}
public ObjectSet<Tile> getTiles(){
return tiles;
}
public int getID(){
return id;
}
public int getCapacity(){
return capacity;
}
public ItemModule items(){
return items;
}
}

View File

@@ -1,26 +0,0 @@
package io.anuke.mindustry.world.blocks.storage;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
public abstract class Unloader extends Block{
protected final int timerUnload = timers++;
public Unloader(String name){
super(name);
update = true;
solid = true;
health = 70;
hasItems = true;
}
@Override
public boolean canDump(Tile tile, Tile to, Item item){
Block block = to.target().block();
return !(block instanceof StorageBlock);
}
@Override
public void setBars(){}
}

View File

@@ -7,7 +7,6 @@ public class Vault extends StorageBlock{
solid = true; solid = true;
update = false; update = false;
destructible = true; destructible = true;
itemCapacity = 1000;
} }
} }

View File

@@ -1,4 +1,4 @@
apply plugin: "java" apply plugin: "java"
sourceCompatibility = 1.8 sourceCompatibility = 1.8
sourceSets.main.java.srcDirs = [ "src/" ] sourceSets.main.java.srcDirs = ["src/"]

View File

@@ -10,18 +10,18 @@ import io.anuke.ucore.util.Pooling;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ByteSerializer implements Serialization { public class ByteSerializer implements Serialization{
@Override @Override
public void write(ByteBuffer byteBuffer, Object o) { public void write(ByteBuffer byteBuffer, Object o){
if(o instanceof FrameworkMessage){ if(o instanceof FrameworkMessage){
byteBuffer.put((byte)-2); //code for framework message byteBuffer.put((byte) -2); //code for framework message
FrameworkSerializer.write(byteBuffer, (FrameworkMessage)o); FrameworkSerializer.write(byteBuffer, (FrameworkMessage) o);
}else { }else{
if (!(o instanceof Packet)) if(!(o instanceof Packet))
throw new RuntimeException("All sent objects must implement be Packets! Class: " + o.getClass()); throw new RuntimeException("All sent objects must implement be Packets! Class: " + o.getClass());
byte id = Registrator.getID(o.getClass()); byte id = Registrator.getID(o.getClass());
if (id == -1) if(id == -1)
throw new RuntimeException("Unregistered class: " + o.getClass()); throw new RuntimeException("Unregistered class: " + o.getClass());
byteBuffer.put(id); byteBuffer.put(id);
((Packet) o).write(byteBuffer); ((Packet) o).write(byteBuffer);
@@ -29,7 +29,7 @@ public class ByteSerializer implements Serialization {
} }
@Override @Override
public Object read(ByteBuffer byteBuffer) { public Object read(ByteBuffer byteBuffer){
byte id = byteBuffer.get(); byte id = byteBuffer.get();
if(id == -2){ if(id == -2){
return FrameworkSerializer.read(byteBuffer); return FrameworkSerializer.read(byteBuffer);
@@ -41,17 +41,17 @@ public class ByteSerializer implements Serialization {
} }
@Override @Override
public int getLengthLength() { public int getLengthLength(){
return 2; return 2;
} }
@Override @Override
public void writeLength(ByteBuffer byteBuffer, int i) { public void writeLength(ByteBuffer byteBuffer, int i){
byteBuffer.putShort((short)i); byteBuffer.putShort((short) i);
} }
@Override @Override
public int readLength(ByteBuffer byteBuffer) { public int readLength(ByteBuffer byteBuffer){
return byteBuffer.getShort(); return byteBuffer.getShort();
} }
} }

View File

@@ -5,32 +5,32 @@ import com.esotericsoftware.kryonet.FrameworkMessage.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
public class FrameworkSerializer { public class FrameworkSerializer{
public static void write(ByteBuffer buffer, FrameworkMessage message){ public static void write(ByteBuffer buffer, FrameworkMessage message){
if(message instanceof Ping){ if(message instanceof Ping){
Ping p = (Ping)message; Ping p = (Ping) message;
buffer.put((byte)0); buffer.put((byte) 0);
buffer.putInt(p.id); buffer.putInt(p.id);
buffer.put(p.isReply ? 1 : (byte)0); buffer.put(p.isReply ? 1 : (byte) 0);
}else if(message instanceof DiscoverHost){ }else if(message instanceof DiscoverHost){
DiscoverHost p = (DiscoverHost)message; DiscoverHost p = (DiscoverHost) message;
buffer.put((byte)1); buffer.put((byte) 1);
}else if(message instanceof KeepAlive){ }else if(message instanceof KeepAlive){
KeepAlive p = (KeepAlive)message; KeepAlive p = (KeepAlive) message;
buffer.put((byte)2); buffer.put((byte) 2);
}else if(message instanceof RegisterUDP){ }else if(message instanceof RegisterUDP){
RegisterUDP p = (RegisterUDP)message; RegisterUDP p = (RegisterUDP) message;
buffer.put((byte)3); buffer.put((byte) 3);
buffer.putInt(p.connectionID); buffer.putInt(p.connectionID);
}else if(message instanceof RegisterTCP){ }else if(message instanceof RegisterTCP){
RegisterTCP p = (RegisterTCP)message; RegisterTCP p = (RegisterTCP) message;
buffer.put((byte)4); buffer.put((byte) 4);
buffer.putInt(p.connectionID); buffer.putInt(p.connectionID);
} }
} }

View File

@@ -35,14 +35,14 @@ public class KryoClient implements ClientProvider{
public KryoClient(){ public KryoClient(){
KryoCore.init(); KryoCore.init();
handler = new ClientDiscoveryHandler() { handler = new ClientDiscoveryHandler(){
@Override @Override
public DatagramPacket onRequestNewDatagramPacket() { public DatagramPacket onRequestNewDatagramPacket(){
return new DatagramPacket(new byte[128], 128); return new DatagramPacket(new byte[128], 128);
} }
@Override @Override
public void onDiscoveredHost(DatagramPacket datagramPacket) { public void onDiscoveredHost(DatagramPacket datagramPacket){
ByteBuffer buffer = ByteBuffer.wrap(datagramPacket.getData()); ByteBuffer buffer = ByteBuffer.wrap(datagramPacket.getData());
Host host = NetworkIO.readServerData(datagramPacket.getAddress().getHostAddress(), buffer); Host host = NetworkIO.readServerData(datagramPacket.getAddress().getHostAddress(), buffer);
for(InetAddress address : foundAddresses){ for(InetAddress address : foundAddresses){
@@ -55,7 +55,7 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void onFinally() { public void onFinally(){
} }
}; };
@@ -65,7 +65,7 @@ public class KryoClient implements ClientProvider{
Listener listener = new Listener(){ Listener listener = new Listener(){
@Override @Override
public void connected (Connection connection) { public void connected(Connection connection){
Connect c = new Connect(); Connect c = new Connect();
c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress(); c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress();
c.id = connection.getID(); c.id = connection.getID();
@@ -75,7 +75,7 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void disconnected (Connection connection) { public void disconnected(Connection connection){
if(connection.getLastProtocolError() != null){ if(connection.getLastProtocolError() != null){
netClient.setQuiet(); netClient.setQuiet();
} }
@@ -85,13 +85,13 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void received (Connection connection, Object object) { public void received(Connection connection, Object object){
if(object instanceof FrameworkMessage) return; if(object instanceof FrameworkMessage) return;
threads.runDelay(() -> { threads.runDelay(() -> {
try{ try{
Net.handleClientReceived(object); Net.handleClientReceived(object);
}catch (Exception e){ }catch(Exception e){
handleException(e); handleException(e);
} }
}); });
@@ -106,12 +106,12 @@ public class KryoClient implements ClientProvider{
} }
} }
private static boolean isLocal(InetAddress addr) { private static boolean isLocal(InetAddress addr){
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true; if(addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true;
try { try{
return NetworkInterface.getByInetAddress(addr) != null; return NetworkInterface.getByInetAddress(addr) != null;
} catch (Exception e) { }catch(Exception e){
return false; return false;
} }
} }
@@ -150,12 +150,12 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void disconnect() { public void disconnect(){
client.close(); client.close();
} }
@Override @Override
public void send(Object object, SendMode mode) { public void send(Object object, SendMode mode){
if(mode == SendMode.tcp){ if(mode == SendMode.tcp){
client.sendTCP(object); client.sendTCP(object);
}else{ }else{
@@ -166,12 +166,12 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void updatePing() { public void updatePing(){
client.updateReturnTripTime(); client.updateReturnTripTime();
} }
@Override @Override
public int getPing() { public int getPing(){
return client.getReturnTripTime(); return client.getReturnTripTime();
} }
@@ -218,7 +218,7 @@ public class KryoClient implements ClientProvider{
public void dispose(){ public void dispose(){
try{ try{
client.dispose(); client.dispose();
}catch (IOException e){ }catch(IOException e){
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }

View File

@@ -10,8 +10,8 @@ import java.util.concurrent.ScheduledExecutorService;
import static io.anuke.mindustry.Vars.headless; import static io.anuke.mindustry.Vars.headless;
/**Utilities and configs for kryo module.*/ /** Utilities and configs for kryo module. */
public class KryoCore { public class KryoCore{
public static boolean fakeLag = false; public static boolean fakeLag = false;
public static final int fakeLagMax = 500; public static final int fakeLagMax = 500;
public static final int fakeLagMin = 0; public static final int fakeLagMin = 0;
@@ -26,7 +26,7 @@ public class KryoCore {
Log.set(fakeLag ? Log.LEVEL_DEBUG : Log.LEVEL_WARN); Log.set(fakeLag ? Log.LEVEL_DEBUG : Log.LEVEL_WARN);
Log.setLogger(new Logger(){ Log.setLogger(new Logger(){
public void log (int level, String category, String message, Throwable ex) { public void log(int level, String category, String message, Throwable ex){
if(fakeLag){ if(fakeLag){
if(message.contains("UDP")){ if(message.contains("UDP")){
lastUDP = true; lastUDP = true;
@@ -45,7 +45,7 @@ public class KryoCore {
builder.append(message); builder.append(message);
if (ex != null) { if(ex != null){
StringWriter writer = new StringWriter(256); StringWriter writer = new StringWriter(256);
ex.printStackTrace(new PrintWriter(writer)); ex.printStackTrace(new PrintWriter(writer));
builder.append('\n'); builder.append('\n');
@@ -60,7 +60,7 @@ public class KryoCore {
}); });
} }
private static int calculateLag() { private static int calculateLag(){
return fakeLagMin + (int)(Math.random() * (fakeLagMax - fakeLagMin)); return fakeLagMin + (int) (Math.random() * (fakeLagMax - fakeLagMin));
} }
} }

View File

@@ -29,7 +29,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
import static io.anuke.mindustry.Vars.threads; import static io.anuke.mindustry.Vars.threads;
public class KryoServer implements ServerProvider { public class KryoServer implements ServerProvider{
final Server server; final Server server;
final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>(); final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>();
final CopyOnWriteArraySet<Integer> missing = new CopyOnWriteArraySet<>(); final CopyOnWriteArraySet<Integer> missing = new CopyOnWriteArraySet<>();
@@ -42,7 +42,7 @@ public class KryoServer implements ServerProvider {
public KryoServer(){ public KryoServer(){
KryoCore.init(); KryoCore.init();
server = new Server(4096*2, 4096, connection -> new ByteSerializer()); server = new Server(4096 * 2, 4096, connection -> new ByteSerializer());
server.setDiscoveryHandler((datagramChannel, fromAddress) -> { server.setDiscoveryHandler((datagramChannel, fromAddress) -> {
ByteBuffer buffer = NetworkIO.writeServerData(); ByteBuffer buffer = NetworkIO.writeServerData();
buffer.position(0); buffer.position(0);
@@ -53,10 +53,10 @@ public class KryoServer implements ServerProvider {
Listener listener = new Listener(){ Listener listener = new Listener(){
@Override @Override
public void connected (Connection connection) { public void connected(Connection connection){
String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress(); String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress();
KryoConnection kn = new KryoConnection(lastconnection ++, ip, connection); KryoConnection kn = new KryoConnection(lastconnection++, ip, connection);
Connect c = new Connect(); Connect c = new Connect();
c.id = kn.id; c.id = kn.id;
@@ -69,7 +69,7 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void disconnected (Connection connection) { public void disconnected(Connection connection){
KryoConnection k = getByKryoID(connection.getID()); KryoConnection k = getByKryoID(connection.getID());
if(k == null) return; if(k == null) return;
@@ -83,14 +83,14 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void received (Connection connection, Object object) { public void received(Connection connection, Object object){
KryoConnection k = getByKryoID(connection.getID()); KryoConnection k = getByKryoID(connection.getID());
if(object instanceof FrameworkMessage || k == null) return; if(object instanceof FrameworkMessage || k == null) return;
threads.runDelay(() -> { threads.runDelay(() -> {
try{ try{
Net.handleServerReceived(k.id, object); Net.handleServerReceived(k.id, object);
}catch (Exception e){ }catch(Exception e){
e.printStackTrace(); e.printStackTrace();
} }
}); });
@@ -110,7 +110,7 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public Array<KryoConnection> getConnections() { public Array<KryoConnection> getConnections(){
array.clear(); array.clear();
for(KryoConnection c : connections){ for(KryoConnection c : connections){
array.add(c); array.add(c);
@@ -120,7 +120,7 @@ public class KryoServer implements ServerProvider {
@Override @Override
public KryoConnection getByID(int id){ public KryoConnection getByID(int id){
for(int i = 0; i < connections.size(); i ++){ for(int i = 0; i < connections.size(); i++){
KryoConnection con = connections.get(i); KryoConnection con = connections.get(i);
if(con.id == id){ if(con.id == id){
return con; return con;
@@ -131,7 +131,7 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void host(int port) throws IOException { public void host(int port) throws IOException{
//attempt to open default ports if they're not already open //attempt to open default ports if they're not already open
//this only opens the default port due to security concerns (?) //this only opens the default port due to security concerns (?)
if(port == Vars.port){ if(port == Vars.port){
@@ -139,7 +139,8 @@ public class KryoServer implements ServerProvider {
try{ try{
if(!UPnP.isMappedTCP(port)) UPnP.openPortTCP(port); if(!UPnP.isMappedTCP(port)) UPnP.openPortTCP(port);
if(!UPnP.isMappedUDP(port)) UPnP.openPortUDP(port); if(!UPnP.isMappedUDP(port)) UPnP.openPortUDP(port);
}catch(Throwable ignored){} }catch(Throwable ignored){
}
}); });
} }
@@ -151,7 +152,7 @@ public class KryoServer implements ServerProvider {
serverThread = new Thread(() -> { serverThread = new Thread(() -> {
try{ try{
server.run(); server.run();
}catch (Throwable e){ }catch(Throwable e){
if(!(e instanceof ClosedSelectorException)) handleException(e); if(!(e instanceof ClosedSelectorException)) handleException(e);
} }
}, "Kryonet Server"); }, "Kryonet Server");
@@ -160,7 +161,7 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void close() { public void close(){
connections.clear(); connections.clear();
lastconnection = 0; lastconnection = 0;
@@ -168,17 +169,17 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void sendStream(int id, Streamable stream) { public void sendStream(int id, Streamable stream){
KryoConnection connection = getByID(id); KryoConnection connection = getByID(id);
if(connection == null) return; if(connection == null) return;
try { try{
if (connection.connection != null) { if(connection.connection != null){
connection.connection.addListener(new InputStreamSender(stream.stream, 512) { connection.connection.addListener(new InputStreamSender(stream.stream, 512){
int id; int id;
protected void start() { protected void start(){
//send an object so the receiving side knows how to handle the following chunks //send an object so the receiving side knows how to handle the following chunks
StreamBegin begin = new StreamBegin(); StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available(); begin.total = stream.stream.available();
@@ -187,14 +188,14 @@ public class KryoServer implements ServerProvider {
id = begin.id; id = begin.id;
} }
protected Object next(byte[] bytes) { protected Object next(byte[] bytes){
StreamChunk chunk = new StreamChunk(); StreamChunk chunk = new StreamChunk();
chunk.id = id; chunk.id = id;
chunk.data = bytes; chunk.data = bytes;
return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it. return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it.
} }
}); });
} else { }else{
int cid; int cid;
StreamBegin begin = new StreamBegin(); StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available(); begin.total = stream.stream.available();
@@ -202,7 +203,7 @@ public class KryoServer implements ServerProvider {
connection.send(begin, SendMode.tcp); connection.send(begin, SendMode.tcp);
cid = begin.id; cid = begin.id;
while (stream.stream.available() > 0) { while(stream.stream.available() > 0){
byte[] bytes = new byte[Math.min(512, stream.stream.available())]; byte[] bytes = new byte[Math.min(512, stream.stream.available())];
stream.stream.read(bytes); stream.stream.read(bytes);
@@ -212,20 +213,20 @@ public class KryoServer implements ServerProvider {
connection.send(chunk, SendMode.tcp); connection.send(chunk, SendMode.tcp);
} }
} }
}catch (IOException e){ }catch(IOException e){
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@Override @Override
public void send(Object object, SendMode mode) { public void send(Object object, SendMode mode){
for(int i = 0; i < connections.size(); i ++){ for(int i = 0; i < connections.size(); i++){
connections.get(i).send(object, mode); connections.get(i).send(object, mode);
} }
} }
@Override @Override
public void sendTo(int id, Object object, SendMode mode) { public void sendTo(int id, Object object, SendMode mode){
NetConnection conn = getByID(id); NetConnection conn = getByID(id);
if(conn == null){ if(conn == null){
if(!missing.contains(id)) if(!missing.contains(id))
@@ -237,8 +238,8 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void sendExcept(int id, Object object, SendMode mode) { public void sendExcept(int id, Object object, SendMode mode){
for(int i = 0; i < connections.size(); i ++){ for(int i = 0; i < connections.size(); i++){
KryoConnection conn = connections.get(i); KryoConnection conn = connections.get(i);
if(conn.id != id) conn.send(object, mode); if(conn.id != id) conn.send(object, mode);
} }
@@ -251,11 +252,13 @@ public class KryoServer implements ServerProvider {
} }
private void handleException(Throwable e){ private void handleException(Throwable e){
Timers.run(0f, () -> { throw new RuntimeException(e);}); Timers.run(0f, () -> {
throw new RuntimeException(e);
});
} }
KryoConnection getByKryoID(int id){ KryoConnection getByKryoID(int id){
for(int i = 0; i < connections.size(); i ++){ for(int i = 0; i < connections.size(); i++){
KryoConnection con = connections.get(i); KryoConnection con = connections.get(i);
if(con.connection != null && con.connection.getID() == id){ if(con.connection != null && con.connection.getID() == id){
return con; return con;
@@ -274,7 +277,7 @@ public class KryoServer implements ServerProvider {
class KryoConnection extends NetConnection{ class KryoConnection extends NetConnection{
public final Connection connection; public final Connection connection;
public KryoConnection(int id, String address, Connection connection) { public KryoConnection(int id, String address, Connection connection){
super(id, address); super(id, address);
this.connection = connection; this.connection = connection;
} }
@@ -286,13 +289,13 @@ public class KryoServer implements ServerProvider {
@Override @Override
public void send(Object object, SendMode mode){ public void send(Object object, SendMode mode){
try { try{
if (mode == SendMode.tcp) { if(mode == SendMode.tcp){
connection.sendTCP(object); connection.sendTCP(object);
} else { }else{
connection.sendUDP(object); connection.sendUDP(object);
} }
}catch (Exception e){ }catch(Exception e){
Log.err(e); Log.err(e);
Log.info("Disconnecting invalid client!"); Log.info("Disconnecting invalid client!");
connection.close(); connection.close();