Merge remote-tracking branch 'fork_master/master'
This commit is contained in:
@@ -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] воду[] для увеличения скорости сверления.
|
||||||
|
|||||||
@@ -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;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
}};
|
}};
|
||||||
|
|||||||
@@ -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);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) -> {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ public enum GameMode{
|
|||||||
}},
|
}},
|
||||||
attack{{
|
attack{{
|
||||||
disableWaves = true;
|
disableWaves = true;
|
||||||
hidden = true;
|
|
||||||
enemyCheat = true;
|
enemyCheat = true;
|
||||||
}},
|
}},
|
||||||
victory{{
|
victory{{
|
||||||
|
|||||||
@@ -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(){
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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){
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package io.anuke.mindustry.world.blocks.distribution;
|
||||||
|
|
||||||
|
public class LiquidTank extends LiquidRouter{
|
||||||
|
|
||||||
|
public LiquidTank(String name){
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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(){}
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ public class Vault extends StorageBlock{
|
|||||||
solid = true;
|
solid = true;
|
||||||
update = false;
|
update = false;
|
||||||
destructible = true;
|
destructible = true;
|
||||||
itemCapacity = 1000;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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/"]
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user