Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f504dd2b5a | ||
|
|
26881fbdb9 | ||
|
|
8d921199fb | ||
|
|
4ffe233321 | ||
|
|
e076de9dcd | ||
|
|
5ce66b0dbb | ||
|
|
6971a76c8e | ||
|
|
d47f86cc21 | ||
|
|
487607e1d6 | ||
|
|
3cefc085bd | ||
|
|
3d8e5bd36a | ||
|
|
e9ed0512f7 | ||
|
|
0cf39bf5c3 | ||
|
|
95a1474b9a | ||
|
|
53aedcee2c | ||
|
|
9758a05002 | ||
|
|
18bb7ba936 | ||
|
|
9f3dcdf727 | ||
|
|
7d2354a653 | ||
|
|
ab21b88001 | ||
|
|
a560978dcf | ||
|
|
047f479a2f | ||
|
|
d78d3daaf9 | ||
|
|
976d0f54b3 | ||
|
|
1c1db3990f | ||
|
|
bcc8f65ac8 | ||
|
|
e043f4bb66 | ||
|
|
9d3dda035c | ||
|
|
6e16aab794 | ||
|
|
c1cf3183ac | ||
|
|
252d0f6aa1 | ||
|
|
1f5a6e1bf8 | ||
|
|
58e3143e2a | ||
|
|
9033ebcfd7 | ||
|
|
1f5e773c77 | ||
|
|
7b1a0a42d4 | ||
|
|
3d78175e50 | ||
|
|
9d2133814c | ||
|
|
6ce013a1eb | ||
|
|
5db8520b74 | ||
|
|
736737f151 | ||
|
|
0c430527b8 | ||
|
|
7871b5bdaa | ||
|
|
124480f96b |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -55,15 +55,6 @@ crash-report-*
|
|||||||
## Robovm
|
## Robovm
|
||||||
/ios/robovm-build/
|
/ios/robovm-build/
|
||||||
|
|
||||||
## GWT
|
|
||||||
/html/war/
|
|
||||||
/html/gwt-unitCache/
|
|
||||||
.apt_generated/
|
|
||||||
.gwt/
|
|
||||||
gwt-unitCache/
|
|
||||||
www-test/
|
|
||||||
.gwt-tmp/
|
|
||||||
|
|
||||||
## Android Studio and Intellij and Android in general
|
## Android Studio and Intellij and Android in general
|
||||||
/android/libs/armeabi/
|
/android/libs/armeabi/
|
||||||
/android/libs/armeabi-v7a/
|
/android/libs/armeabi-v7a/
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import io.anuke.arc.util.*;
|
|||||||
import io.anuke.arc.util.serialization.*;
|
import io.anuke.arc.util.serialization.*;
|
||||||
import io.anuke.mindustry.game.Saves.*;
|
import io.anuke.mindustry.game.Saves.*;
|
||||||
import io.anuke.mindustry.io.*;
|
import io.anuke.mindustry.io.*;
|
||||||
import io.anuke.mindustry.mod.*;
|
|
||||||
import io.anuke.mindustry.ui.dialogs.*;
|
import io.anuke.mindustry.ui.dialogs.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@@ -71,11 +70,11 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shareFile(FileHandle file){
|
public void shareFile(Fi file){
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showFileChooser(boolean open, String extension, Cons<FileHandle> cons){
|
public void showFileChooser(boolean open, String extension, Cons<Fi> cons){
|
||||||
if(VERSION.SDK_INT >= VERSION_CODES.Q){
|
if(VERSION.SDK_INT >= VERSION_CODES.Q){
|
||||||
Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT);
|
Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT);
|
||||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||||
@@ -86,7 +85,7 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
|
|
||||||
if(uri.getPath().contains("(invalid)")) return;
|
if(uri.getPath().contains("(invalid)")) return;
|
||||||
|
|
||||||
Core.app.post(() -> Core.app.post(() -> cons.get(new FileHandle(uri.getPath()){
|
Core.app.post(() -> Core.app.post(() -> cons.get(new Fi(uri.getPath()){
|
||||||
@Override
|
@Override
|
||||||
public InputStream read(){
|
public InputStream read(){
|
||||||
try{
|
try{
|
||||||
@@ -144,7 +143,7 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
useImmersiveMode = true;
|
useImmersiveMode = true;
|
||||||
depth = 0;
|
depth = 0;
|
||||||
hideStatusBar = true;
|
hideStatusBar = true;
|
||||||
errorHandler = ModCrashHandler::handle;
|
//errorHandler = ModCrashHandler::handle;
|
||||||
}});
|
}});
|
||||||
checkFiles(getIntent());
|
checkFiles(getIntent());
|
||||||
}
|
}
|
||||||
@@ -186,7 +185,7 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
Core.app.post(() -> Core.app.post(() -> {
|
Core.app.post(() -> Core.app.post(() -> {
|
||||||
if(save){ //open save
|
if(save){ //open save
|
||||||
System.out.println("Opening save.");
|
System.out.println("Opening save.");
|
||||||
FileHandle file = Core.files.local("temp-save." + saveExtension);
|
Fi file = Core.files.local("temp-save." + saveExtension);
|
||||||
file.write(inStream, false);
|
file.write(inStream, false);
|
||||||
if(SaveIO.isSaveValid(file)){
|
if(SaveIO.isSaveValid(file)){
|
||||||
try{
|
try{
|
||||||
@@ -199,7 +198,7 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
ui.showErrorMessage("$save.import.invalid");
|
ui.showErrorMessage("$save.import.invalid");
|
||||||
}
|
}
|
||||||
}else if(map){ //open map
|
}else if(map){ //open map
|
||||||
FileHandle file = Core.files.local("temp-map." + mapExtension);
|
Fi file = Core.files.local("temp-map." + mapExtension);
|
||||||
file.write(inStream, false);
|
file.write(inStream, false);
|
||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
System.out.println("Opening map.");
|
System.out.println("Opening map.");
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry;
|
|||||||
|
|
||||||
import android.annotation.*;
|
import android.annotation.*;
|
||||||
import android.os.*;
|
import android.os.*;
|
||||||
|
import android.os.Build.*;
|
||||||
import com.android.dex.*;
|
import com.android.dex.*;
|
||||||
import com.android.dx.cf.direct.*;
|
import com.android.dx.cf.direct.*;
|
||||||
import com.android.dx.command.dexer.*;
|
import com.android.dx.command.dexer.*;
|
||||||
@@ -177,7 +178,8 @@ public class AndroidRhinoContext{
|
|||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
return new DexClassLoader(dexFile.getPath(), ((AndroidApplication)Core.app).getContext().getCacheDir().getAbsolutePath(), null, getParent()).loadClass(name);
|
android.content.Context context = ((AndroidApplication)Core.app).getContext();
|
||||||
|
return new DexClassLoader(dexFile.getPath(), VERSION.SDK_INT >= 21 ? context.getCodeCacheDir().getPath() : context.getCacheDir().getAbsolutePath(), null, getParent()).loadClass(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
BIN
core/assets-raw/fonts/RussoOne-Regular.ttf
Normal file
BIN
core/assets-raw/fonts/RussoOne-Regular.ttf
Normal file
Binary file not shown.
@@ -100,8 +100,11 @@ mod.enabled = [lightgray]Enabled
|
|||||||
mod.disabled = [scarlet]Disabled
|
mod.disabled = [scarlet]Disabled
|
||||||
mod.disable = Disable
|
mod.disable = Disable
|
||||||
mod.delete.error = Unable to delete mod. File may be in use.
|
mod.delete.error = Unable to delete mod. File may be in use.
|
||||||
mod.requiresversion = [scarlet]Requires game version: [accent]{0}
|
mod.requiresversion = [scarlet]Requires min game version: [accent]{0}
|
||||||
mod.missingdependencies = [scarlet]Missing dependencies: {0}
|
mod.missingdependencies = [scarlet]Missing dependencies: {0}
|
||||||
|
mod.erroredcontent = [scarlet]Content Errors
|
||||||
|
mod.errors = Errors have occurred loading content.
|
||||||
|
mod.noerrorplay = [scarlet]You have mods with errors.[] Either disable the affected mods or fix the errors before playing.
|
||||||
mod.nowdisabled = [scarlet]Mod '{0}' is missing dependencies:[accent] {1}\n[lightgray]These mods need to be downloaded first.\nThis mod will be automatically disabled.
|
mod.nowdisabled = [scarlet]Mod '{0}' is missing dependencies:[accent] {1}\n[lightgray]These mods need to be downloaded first.\nThis mod will be automatically disabled.
|
||||||
mod.enable = Enable
|
mod.enable = Enable
|
||||||
mod.requiresrestart = The game will now close to apply the mod changes.
|
mod.requiresrestart = The game will now close to apply the mod changes.
|
||||||
@@ -705,7 +708,6 @@ keybind.pick.name = Pick Block
|
|||||||
keybind.break_block.name = Break Block
|
keybind.break_block.name = Break Block
|
||||||
keybind.deselect.name = Deselect
|
keybind.deselect.name = Deselect
|
||||||
keybind.shoot.name = Shoot
|
keybind.shoot.name = Shoot
|
||||||
keybind.zoom_hold.name = Zoom Hold
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pause
|
keybind.pause.name = Pause
|
||||||
@@ -1046,7 +1048,7 @@ unit.eradicator.name = Eradicator
|
|||||||
unit.lich.name = Lich
|
unit.lich.name = Lich
|
||||||
unit.reaper.name = Reaper
|
unit.reaper.name = Reaper
|
||||||
tutorial.next = [lightgray]<Tap to continue>
|
tutorial.next = [lightgray]<Tap to continue>
|
||||||
tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nUse [accent][[WASD][] to move.\n[accent]Hold [[Ctrl] while scrolling[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nUse[accent] [[WASD][] to move.\n[accent]Scroll[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
||||||
tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper
|
||||||
tutorial.drill = Mining manually is inefficient.\n[accent]Drills[] can mine automatically.\nClick the drill tab in the bottom right.\nSelect the[accent] mechanical drill[]. Place it on a copper vein by clicking.\nYou can also select the drill by tapping [accent][[2][] then [accent][[1][] quickly, regardless of which tab is open.\n[accent]Right-click[] to stop building.
|
tutorial.drill = Mining manually is inefficient.\n[accent]Drills[] can mine automatically.\nClick the drill tab in the bottom right.\nSelect the[accent] mechanical drill[]. Place it on a copper vein by clicking.\nYou can also select the drill by tapping [accent][[2][] then [accent][[1][] quickly, regardless of which tab is open.\n[accent]Right-click[] to stop building.
|
||||||
tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills[] can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement.
|
tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills[] can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement.
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Pick Block
|
|||||||
keybind.break_block.name = Break Block
|
keybind.break_block.name = Break Block
|
||||||
keybind.deselect.name = Odznačit
|
keybind.deselect.name = Odznačit
|
||||||
keybind.shoot.name = Střílet
|
keybind.shoot.name = Střílet
|
||||||
keybind.zoom_hold.name = Přiblížení-podržení
|
|
||||||
keybind.zoom.name = přiblížení
|
keybind.zoom.name = přiblížení
|
||||||
keybind.menu.name = Hlavní nabídka
|
keybind.menu.name = Hlavní nabídka
|
||||||
keybind.pause.name = pauza
|
keybind.pause.name = pauza
|
||||||
|
|||||||
@@ -672,7 +672,6 @@ keybind.pick.name = Block Auswählen
|
|||||||
keybind.break_block.name = Block zerstören
|
keybind.break_block.name = Block zerstören
|
||||||
keybind.deselect.name = Auswahl aufheben
|
keybind.deselect.name = Auswahl aufheben
|
||||||
keybind.shoot.name = Schießen
|
keybind.shoot.name = Schießen
|
||||||
keybind.zoom_hold.name = Zoom halten
|
|
||||||
keybind.zoom.name = Zoomen
|
keybind.zoom.name = Zoomen
|
||||||
keybind.menu.name = Menü
|
keybind.menu.name = Menü
|
||||||
keybind.pause.name = Pause
|
keybind.pause.name = Pause
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Pick Block
|
|||||||
keybind.break_block.name = Destruir Bloque
|
keybind.break_block.name = Destruir Bloque
|
||||||
keybind.deselect.name = Deseleccionar
|
keybind.deselect.name = Deseleccionar
|
||||||
keybind.shoot.name = Disparar
|
keybind.shoot.name = Disparar
|
||||||
keybind.zoom_hold.name = Mantener Zoom
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menú
|
keybind.menu.name = Menú
|
||||||
keybind.pause.name = Pausa
|
keybind.pause.name = Pausa
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Vali blokk
|
|||||||
keybind.break_block.name = Hävita blokk
|
keybind.break_block.name = Hävita blokk
|
||||||
keybind.deselect.name = Tühista valik
|
keybind.deselect.name = Tühista valik
|
||||||
keybind.shoot.name = Tulista
|
keybind.shoot.name = Tulista
|
||||||
keybind.zoom_hold.name = Suumimise režiim
|
|
||||||
keybind.zoom.name = Muuda suumi
|
keybind.zoom.name = Muuda suumi
|
||||||
keybind.menu.name = Menüü
|
keybind.menu.name = Menüü
|
||||||
keybind.pause.name = Paus
|
keybind.pause.name = Paus
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Jaso blokea
|
|||||||
keybind.break_block.name = Apurtu blokea
|
keybind.break_block.name = Apurtu blokea
|
||||||
keybind.deselect.name = Deshautatu
|
keybind.deselect.name = Deshautatu
|
||||||
keybind.shoot.name = Tirokatu
|
keybind.shoot.name = Tirokatu
|
||||||
keybind.zoom_hold.name = Zoom mantenduz
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menua
|
keybind.menu.name = Menua
|
||||||
keybind.pause.name = Pausatu
|
keybind.pause.name = Pausatu
|
||||||
|
|||||||
@@ -547,7 +547,6 @@ keybind.pick.name = Pick Block
|
|||||||
keybind.break_block.name = Break Block
|
keybind.break_block.name = Break Block
|
||||||
keybind.deselect.name = Deselect
|
keybind.deselect.name = Deselect
|
||||||
keybind.shoot.name = Shoot
|
keybind.shoot.name = Shoot
|
||||||
keybind.zoom_hold.name = Zoom Hold
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pause
|
keybind.pause.name = Pause
|
||||||
|
|||||||
@@ -702,7 +702,6 @@ keybind.pick.name = Choisir un bloc
|
|||||||
keybind.break_block.name = Supprimer un bloc
|
keybind.break_block.name = Supprimer un bloc
|
||||||
keybind.deselect.name = Désélectionner
|
keybind.deselect.name = Désélectionner
|
||||||
keybind.shoot.name = Tirer
|
keybind.shoot.name = Tirer
|
||||||
keybind.zoom_hold.name = Maintenir pour zoomer
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pause
|
keybind.pause.name = Pause
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Choisir un bloc
|
|||||||
keybind.break_block.name = Supprimer un bloc
|
keybind.break_block.name = Supprimer un bloc
|
||||||
keybind.deselect.name = Déselectionner
|
keybind.deselect.name = Déselectionner
|
||||||
keybind.shoot.name = Tirer
|
keybind.shoot.name = Tirer
|
||||||
keybind.zoom_hold.name = Tenir le zoom
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pause
|
keybind.pause.name = Pause
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Memilih Blok
|
|||||||
keybind.break_block.name = Menghancurkan Blok
|
keybind.break_block.name = Menghancurkan Blok
|
||||||
keybind.deselect.name = Batal Memilih
|
keybind.deselect.name = Batal Memilih
|
||||||
keybind.shoot.name = Menembak
|
keybind.shoot.name = Menembak
|
||||||
keybind.zoom_hold.name = Tahan Mode Zoom
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Jeda
|
keybind.pause.name = Jeda
|
||||||
|
|||||||
@@ -699,7 +699,6 @@ keybind.pick.name = Scegli Blocco
|
|||||||
keybind.break_block.name = Rompi Blocco
|
keybind.break_block.name = Rompi Blocco
|
||||||
keybind.deselect.name = Deseleziona
|
keybind.deselect.name = Deseleziona
|
||||||
keybind.shoot.name = Spara
|
keybind.shoot.name = Spara
|
||||||
keybind.zoom_hold.name = Attiva Zoom
|
|
||||||
keybind.zoom.name = Esegui Zoom
|
keybind.zoom.name = Esegui Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pausa
|
keybind.pause.name = Pausa
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = ブロックの選択
|
|||||||
keybind.break_block.name = ブロックの破壊
|
keybind.break_block.name = ブロックの破壊
|
||||||
keybind.deselect.name = 選択解除
|
keybind.deselect.name = 選択解除
|
||||||
keybind.shoot.name = ショット
|
keybind.shoot.name = ショット
|
||||||
keybind.zoom_hold.name = 長押しズーム
|
|
||||||
keybind.zoom.name = ズーム
|
keybind.zoom.name = ズーム
|
||||||
keybind.menu.name = メニュー
|
keybind.menu.name = メニュー
|
||||||
keybind.pause.name = ポーズ
|
keybind.pause.name = ポーズ
|
||||||
|
|||||||
@@ -704,7 +704,6 @@ keybind.pick.name = 블록 선택
|
|||||||
keybind.break_block.name = 블록 파괴
|
keybind.break_block.name = 블록 파괴
|
||||||
keybind.deselect.name = 선택해제
|
keybind.deselect.name = 선택해제
|
||||||
keybind.shoot.name = 사격
|
keybind.shoot.name = 사격
|
||||||
keybind.zoom_hold.name = 길게 확대
|
|
||||||
keybind.zoom.name = 확대
|
keybind.zoom.name = 확대
|
||||||
keybind.menu.name = 메뉴
|
keybind.menu.name = 메뉴
|
||||||
keybind.pause.name = 일시중지
|
keybind.pause.name = 일시중지
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Pick Block
|
|||||||
keybind.break_block.name = Break Block
|
keybind.break_block.name = Break Block
|
||||||
keybind.deselect.name = Deselect
|
keybind.deselect.name = Deselect
|
||||||
keybind.shoot.name = Shoot
|
keybind.shoot.name = Shoot
|
||||||
keybind.zoom_hold.name = Zoom Hold
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pause
|
keybind.pause.name = Pause
|
||||||
|
|||||||
@@ -653,7 +653,6 @@ keybind.pick.name = Pick Block
|
|||||||
keybind.break_block.name = Break Block
|
keybind.break_block.name = Break Block
|
||||||
keybind.deselect.name = Deselect
|
keybind.deselect.name = Deselect
|
||||||
keybind.shoot.name = Shoot
|
keybind.shoot.name = Shoot
|
||||||
keybind.zoom_hold.name = Zoom Hold
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pause
|
keybind.pause.name = Pause
|
||||||
|
|||||||
@@ -699,7 +699,6 @@ keybind.pick.name = Wybierz Blok
|
|||||||
keybind.break_block.name = Zniszcz Blok
|
keybind.break_block.name = Zniszcz Blok
|
||||||
keybind.deselect.name = Odznacz
|
keybind.deselect.name = Odznacz
|
||||||
keybind.shoot.name = Strzelanie
|
keybind.shoot.name = Strzelanie
|
||||||
keybind.zoom_hold.name = Inicjator przybliżania
|
|
||||||
keybind.zoom.name = Przybliżanie
|
keybind.zoom.name = Przybliżanie
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pauza
|
keybind.pause.name = Pauza
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Pegar bloco
|
|||||||
keybind.break_block.name = Quebrar bloco
|
keybind.break_block.name = Quebrar bloco
|
||||||
keybind.deselect.name = Deselecionar
|
keybind.deselect.name = Deselecionar
|
||||||
keybind.shoot.name = Atirar
|
keybind.shoot.name = Atirar
|
||||||
keybind.zoom_hold.name = segurar_zoom
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pausar
|
keybind.pause.name = Pausar
|
||||||
|
|||||||
@@ -700,7 +700,6 @@ keybind.pick.name = Pegar bloco
|
|||||||
keybind.break_block.name = Quebrar bloco
|
keybind.break_block.name = Quebrar bloco
|
||||||
keybind.deselect.name = Deselecionar
|
keybind.deselect.name = Deselecionar
|
||||||
keybind.shoot.name = Atirar
|
keybind.shoot.name = Atirar
|
||||||
keybind.zoom_hold.name = segurar Zoom
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pausar
|
keybind.pause.name = Pausar
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ mods.alphainfo = Имейте в виду, что модификации нах
|
|||||||
mods.alpha = [accent](Альфа)
|
mods.alpha = [accent](Альфа)
|
||||||
mods = Модификации
|
mods = Модификации
|
||||||
mods.none = [LIGHT_GRAY]Модификации не найдены!
|
mods.none = [LIGHT_GRAY]Модификации не найдены!
|
||||||
mods.guide = Руководство по созданию модификаций
|
mods.guide = Руководство по модам
|
||||||
mods.report = Доложить об ошибке
|
mods.report = Доложить об ошибке
|
||||||
mods.openfolder = Открыть папку с модификациями
|
mods.openfolder = Открыть папку с модификациями
|
||||||
mod.enabled = [lightgray]Включён
|
mod.enabled = [lightgray]Включён
|
||||||
@@ -107,7 +107,7 @@ mod.enable = Вкл.
|
|||||||
mod.requiresrestart = Теперь игра закроется, чтобы применить изменения в модификациях.
|
mod.requiresrestart = Теперь игра закроется, чтобы применить изменения в модификациях.
|
||||||
mod.reloadrequired = [scarlet]Необходим перезапуск
|
mod.reloadrequired = [scarlet]Необходим перезапуск
|
||||||
mod.import = Импортировать модификацию
|
mod.import = Импортировать модификацию
|
||||||
mod.import.github = Импортировать модификацию с GitHub
|
mod.import.github = Импортировать мод с GitHub
|
||||||
mod.item.remove = Этот предмет является частью модификации [accent]«{0}»[]. Чтобы удалить его, удалите саму модификацию.
|
mod.item.remove = Этот предмет является частью модификации [accent]«{0}»[]. Чтобы удалить его, удалите саму модификацию.
|
||||||
mod.remove.confirm = Этот мод будет удалён.
|
mod.remove.confirm = Этот мод будет удалён.
|
||||||
mod.author = [LIGHT_GRAY]Автор:[] {0}
|
mod.author = [LIGHT_GRAY]Автор:[] {0}
|
||||||
@@ -315,7 +315,7 @@ waves.invalid = Неверные волны в буфере обмена.
|
|||||||
waves.copied = Волны скопированы.
|
waves.copied = Волны скопированы.
|
||||||
waves.none = Враги не были определены.\nОбратите внимание, что пустые волны будут автоматически заменены обычной волной.
|
waves.none = Враги не были определены.\nОбратите внимание, что пустые волны будут автоматически заменены обычной волной.
|
||||||
editor.default = [lightgray]<По умолчанию>
|
editor.default = [lightgray]<По умолчанию>
|
||||||
details = Подробная информация…
|
details = Подробности…
|
||||||
edit = Редактировать…
|
edit = Редактировать…
|
||||||
editor.name = Название:
|
editor.name = Название:
|
||||||
editor.spawn = Создать боевую единицу
|
editor.spawn = Создать боевую единицу
|
||||||
@@ -704,7 +704,6 @@ keybind.pick.name = Выбрать блок
|
|||||||
keybind.break_block.name = Разрушить блок
|
keybind.break_block.name = Разрушить блок
|
||||||
keybind.deselect.name = Снять выделение
|
keybind.deselect.name = Снять выделение
|
||||||
keybind.shoot.name = Выстрел
|
keybind.shoot.name = Выстрел
|
||||||
keybind.zoom_hold.name = Управление масштабом
|
|
||||||
keybind.zoom.name = Приблизить/Отдалить
|
keybind.zoom.name = Приблизить/Отдалить
|
||||||
keybind.menu.name = Меню
|
keybind.menu.name = Меню
|
||||||
keybind.pause.name = Пауза
|
keybind.pause.name = Пауза
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Pick Block
|
|||||||
keybind.break_block.name = Break Block
|
keybind.break_block.name = Break Block
|
||||||
keybind.deselect.name = Deselect
|
keybind.deselect.name = Deselect
|
||||||
keybind.shoot.name = Shoot
|
keybind.shoot.name = Shoot
|
||||||
keybind.zoom_hold.name = Zoom Hold
|
|
||||||
keybind.zoom.name = Zoom
|
keybind.zoom.name = Zoom
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Pause
|
keybind.pause.name = Pause
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Pick Block
|
|||||||
keybind.break_block.name = Break Block
|
keybind.break_block.name = Break Block
|
||||||
keybind.deselect.name = Eldeki yapiyi birak
|
keybind.deselect.name = Eldeki yapiyi birak
|
||||||
keybind.shoot.name = Sik
|
keybind.shoot.name = Sik
|
||||||
keybind.zoom_hold.name = Yaklasma basili tutmasi
|
|
||||||
keybind.zoom.name = Yaklas
|
keybind.zoom.name = Yaklas
|
||||||
keybind.menu.name = Menu
|
keybind.menu.name = Menu
|
||||||
keybind.pause.name = Durdur
|
keybind.pause.name = Durdur
|
||||||
|
|||||||
@@ -652,7 +652,6 @@ keybind.pick.name = Blok Seç
|
|||||||
keybind.break_block.name = Blok Kır
|
keybind.break_block.name = Blok Kır
|
||||||
keybind.deselect.name = Seçimleri Kaldır
|
keybind.deselect.name = Seçimleri Kaldır
|
||||||
keybind.shoot.name = Ateş Et
|
keybind.shoot.name = Ateş Et
|
||||||
keybind.zoom_hold.name = Zumu Sabit Tutma
|
|
||||||
keybind.zoom.name = Zum
|
keybind.zoom.name = Zum
|
||||||
keybind.menu.name = Menü
|
keybind.menu.name = Menü
|
||||||
keybind.pause.name = Durdur
|
keybind.pause.name = Durdur
|
||||||
|
|||||||
@@ -696,7 +696,6 @@ keybind.pick.name = Вибрати блок
|
|||||||
keybind.break_block.name = Зламати блок
|
keybind.break_block.name = Зламати блок
|
||||||
keybind.deselect.name = Скасувати
|
keybind.deselect.name = Скасувати
|
||||||
keybind.shoot.name = Постріл
|
keybind.shoot.name = Постріл
|
||||||
keybind.zoom_hold.name = Керування масштабом
|
|
||||||
keybind.zoom.name = Приблизити
|
keybind.zoom.name = Приблизити
|
||||||
keybind.menu.name = Меню
|
keybind.menu.name = Меню
|
||||||
keybind.pause.name = Пауза
|
keybind.pause.name = Пауза
|
||||||
|
|||||||
@@ -699,7 +699,6 @@ keybind.pick.name = 选择方块
|
|||||||
keybind.break_block.name = 破坏方块
|
keybind.break_block.name = 破坏方块
|
||||||
keybind.deselect.name = 取消选择
|
keybind.deselect.name = 取消选择
|
||||||
keybind.shoot.name = 射击
|
keybind.shoot.name = 射击
|
||||||
keybind.zoom_hold.name = 按住调整缩放
|
|
||||||
keybind.zoom.name = 缩放
|
keybind.zoom.name = 缩放
|
||||||
keybind.menu.name = 菜单
|
keybind.menu.name = 菜单
|
||||||
keybind.pause.name = 暂停
|
keybind.pause.name = 暂停
|
||||||
|
|||||||
@@ -680,7 +680,6 @@ keybind.pick.name = 選擇方塊
|
|||||||
keybind.break_block.name = 移除方塊
|
keybind.break_block.name = 移除方塊
|
||||||
keybind.deselect.name = 取消選取
|
keybind.deselect.name = 取消選取
|
||||||
keybind.shoot.name = 射擊
|
keybind.shoot.name = 射擊
|
||||||
keybind.zoom_hold.name = 按住縮放
|
|
||||||
keybind.zoom.name = 縮放
|
keybind.zoom.name = 縮放
|
||||||
keybind.menu.name = 主選單
|
keybind.menu.name = 主選單
|
||||||
keybind.pause.name = 暫停遊戲
|
keybind.pause.name = 暫停遊戲
|
||||||
|
|||||||
Binary file not shown.
@@ -16,6 +16,7 @@ const run = method => new java.lang.Runnable(){run: method}
|
|||||||
const boolf = method => new Boolf(){get: method}
|
const boolf = method => new Boolf(){get: method}
|
||||||
const boolp = method => new Boolp(){get: method}
|
const boolp = method => new Boolp(){get: method}
|
||||||
const cons = method => new Cons(){get: method}
|
const cons = method => new Cons(){get: method}
|
||||||
|
const prov = method => new Prov(){get: method}
|
||||||
const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer}))
|
const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer}))
|
||||||
const Calls = Packages.io.anuke.mindustry.gen.Call
|
const Calls = Packages.io.anuke.mindustry.gen.Call
|
||||||
importPackage(Packages.io.anuke.arc)
|
importPackage(Packages.io.anuke.arc)
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
|||||||
for(ApplicationListener listener : modules){
|
for(ApplicationListener listener : modules){
|
||||||
listener.init();
|
listener.init();
|
||||||
}
|
}
|
||||||
mods.each(Mod::init);
|
mods.eachClass(Mod::init);
|
||||||
finished = true;
|
finished = true;
|
||||||
Events.fire(new ClientLoadEvent());
|
Events.fire(new ClientLoadEvent());
|
||||||
super.resize(graphics.getWidth(), graphics.getHeight());
|
super.resize(graphics.getWidth(), graphics.getHeight());
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import io.anuke.arc.files.*;
|
|||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.io.*;
|
||||||
import io.anuke.mindustry.ai.*;
|
import io.anuke.mindustry.ai.*;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
@@ -124,21 +125,21 @@ public class Vars implements Loadable{
|
|||||||
/** whether typing into the console is enabled - developers only */
|
/** whether typing into the console is enabled - developers only */
|
||||||
public static boolean enableConsole = false;
|
public static boolean enableConsole = false;
|
||||||
/** application data directory, equivalent to {@link io.anuke.arc.Settings#getDataDirectory()} */
|
/** application data directory, equivalent to {@link io.anuke.arc.Settings#getDataDirectory()} */
|
||||||
public static FileHandle dataDirectory;
|
public static Fi dataDirectory;
|
||||||
/** data subdirectory used for screenshots */
|
/** data subdirectory used for screenshots */
|
||||||
public static FileHandle screenshotDirectory;
|
public static Fi screenshotDirectory;
|
||||||
/** data subdirectory used for custom mmaps */
|
/** data subdirectory used for custom mmaps */
|
||||||
public static FileHandle customMapDirectory;
|
public static Fi customMapDirectory;
|
||||||
/** data subdirectory used for custom mmaps */
|
/** data subdirectory used for custom mmaps */
|
||||||
public static FileHandle mapPreviewDirectory;
|
public static Fi mapPreviewDirectory;
|
||||||
/** tmp subdirectory for map conversion */
|
/** tmp subdirectory for map conversion */
|
||||||
public static FileHandle tmpDirectory;
|
public static Fi tmpDirectory;
|
||||||
/** data subdirectory used for saves */
|
/** data subdirectory used for saves */
|
||||||
public static FileHandle saveDirectory;
|
public static Fi saveDirectory;
|
||||||
/** data subdirectory used for mods */
|
/** data subdirectory used for mods */
|
||||||
public static FileHandle modDirectory;
|
public static Fi modDirectory;
|
||||||
/** data subdirectory used for schematics */
|
/** data subdirectory used for schematics */
|
||||||
public static FileHandle schematicDirectory;
|
public static Fi schematicDirectory;
|
||||||
/** map file extension */
|
/** map file extension */
|
||||||
public static final String mapExtension = "msav";
|
public static final String mapExtension = "msav";
|
||||||
/** save file extension */
|
/** save file extension */
|
||||||
@@ -195,6 +196,7 @@ public class Vars implements Loadable{
|
|||||||
|
|
||||||
public static void init(){
|
public static void init(){
|
||||||
Serialization.init();
|
Serialization.init();
|
||||||
|
DefaultSerializers.typeMappings.put("io.anuke.mindustry.type.ContentType", "io.anuke.mindustry.ctype.ContentType");
|
||||||
|
|
||||||
if(loadLocales){
|
if(loadLocales){
|
||||||
//load locales
|
//load locales
|
||||||
@@ -315,7 +317,7 @@ public class Vars implements Loadable{
|
|||||||
|
|
||||||
try{
|
try{
|
||||||
//try loading external bundle
|
//try loading external bundle
|
||||||
FileHandle handle = Core.files.local("bundle");
|
Fi handle = Core.files.local("bundle");
|
||||||
|
|
||||||
Locale locale = Locale.ENGLISH;
|
Locale locale = Locale.ENGLISH;
|
||||||
Core.bundle = I18NBundle.createBundle(handle, locale);
|
Core.bundle = I18NBundle.createBundle(handle, locale);
|
||||||
@@ -328,7 +330,7 @@ public class Vars implements Loadable{
|
|||||||
}catch(Throwable e){
|
}catch(Throwable e){
|
||||||
//no external bundle found
|
//no external bundle found
|
||||||
|
|
||||||
FileHandle handle = Core.files.internal("bundles/bundle");
|
Fi handle = Core.files.internal("bundles/bundle");
|
||||||
Locale locale;
|
Locale locale;
|
||||||
String loc = Core.settings.getString("locale");
|
String loc = Core.settings.getString("locale");
|
||||||
if(loc.equals("default")){
|
if(loc.equals("default")){
|
||||||
|
|||||||
@@ -1542,7 +1542,7 @@ public class Blocks implements ContentList{
|
|||||||
Items.silicon, Bullets.artilleryHoming,
|
Items.silicon, Bullets.artilleryHoming,
|
||||||
Items.pyratite, Bullets.artilleryIncendiary,
|
Items.pyratite, Bullets.artilleryIncendiary,
|
||||||
Items.blastCompound, Bullets.artilleryExplosive,
|
Items.blastCompound, Bullets.artilleryExplosive,
|
||||||
Items.plastanium, Bullets.arilleryPlastic
|
Items.plastanium, Bullets.artilleryPlastic
|
||||||
);
|
);
|
||||||
size = 3;
|
size = 3;
|
||||||
shots = 4;
|
shots = 4;
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class Bullets implements ContentList{
|
|||||||
public static BulletType
|
public static BulletType
|
||||||
|
|
||||||
//artillery
|
//artillery
|
||||||
artilleryDense, arilleryPlastic, artilleryPlasticFrag, artilleryHoming, artilleryIncendiary, artilleryExplosive, artilleryUnit,
|
artilleryDense, artilleryPlastic, artilleryPlasticFrag, artilleryHoming, artilleryIncendiary, artilleryExplosive, artilleryUnit,
|
||||||
|
|
||||||
//flak
|
//flak
|
||||||
flakScrap, flakLead, flakPlastic, flakExplosive, flakSurge, flakGlass, glassFrag,
|
flakScrap, flakLead, flakPlastic, flakExplosive, flakSurge, flakGlass, glassFrag,
|
||||||
@@ -65,7 +65,7 @@ public class Bullets implements ContentList{
|
|||||||
despawnEffect = Fx.none;
|
despawnEffect = Fx.none;
|
||||||
}};
|
}};
|
||||||
|
|
||||||
arilleryPlastic = new ArtilleryBulletType(3.4f, 0, "shell"){{
|
artilleryPlastic = new ArtilleryBulletType(3.4f, 0, "shell"){{
|
||||||
hitEffect = Fx.plasticExplosion;
|
hitEffect = Fx.plasticExplosion;
|
||||||
knockback = 1f;
|
knockback = 1f;
|
||||||
lifetime = 55f;
|
lifetime = 55f;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import io.anuke.arc.util.ArcAnnotate.*;
|
|||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.bullet.*;
|
import io.anuke.mindustry.entities.bullet.*;
|
||||||
import io.anuke.mindustry.mod.Mods.*;
|
import io.anuke.mindustry.mod.Mods.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
@@ -25,6 +26,7 @@ public class ContentLoader{
|
|||||||
private Array<Content>[] contentMap = new Array[ContentType.values().length];
|
private Array<Content>[] contentMap = new Array[ContentType.values().length];
|
||||||
private MappableContent[][] temporaryMapper;
|
private MappableContent[][] temporaryMapper;
|
||||||
private @Nullable LoadedMod currentMod;
|
private @Nullable LoadedMod currentMod;
|
||||||
|
private @Nullable Content lastAdded;
|
||||||
private ObjectSet<Cons<Content>> initialization = new ObjectSet<>();
|
private ObjectSet<Cons<Content>> initialization = new ObjectSet<>();
|
||||||
private ContentList[] content = {
|
private ContentList[] content = {
|
||||||
new Fx(),
|
new Fx(),
|
||||||
@@ -114,8 +116,8 @@ public class ContentLoader{
|
|||||||
try{
|
try{
|
||||||
callable.get(content);
|
callable.get(content);
|
||||||
}catch(Throwable e){
|
}catch(Throwable e){
|
||||||
if(content.mod != null){
|
if(content.minfo.mod != null){
|
||||||
mods.handleError(new ModLoadException(content, e), content.mod);
|
mods.handleContentError(content, e);
|
||||||
}else{
|
}else{
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@@ -146,11 +148,27 @@ public class ContentLoader{
|
|||||||
//clear all content, currently not used
|
//clear all content, currently not used
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get last piece of content created for error-handling purposes. */
|
||||||
|
public @Nullable Content getLastAdded(){
|
||||||
|
return lastAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove last content added in case of an exception. */
|
||||||
|
public void removeLast(){
|
||||||
|
if(lastAdded != null && contentMap[lastAdded.getContentType().ordinal()].peek() == lastAdded){
|
||||||
|
contentMap[lastAdded.getContentType().ordinal()].pop();
|
||||||
|
if(lastAdded instanceof MappableContent){
|
||||||
|
contentNameMap[lastAdded.getContentType().ordinal()].remove(((MappableContent)lastAdded).name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void handleContent(Content content){
|
public void handleContent(Content content){
|
||||||
|
this.lastAdded = content;
|
||||||
contentMap[content.getContentType().ordinal()].add(content);
|
contentMap[content.getContentType().ordinal()].add(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCurrentMod(LoadedMod mod){
|
public void setCurrentMod(@Nullable LoadedMod mod){
|
||||||
this.currentMod = mod;
|
this.currentMod = mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +181,7 @@ public class ContentLoader{
|
|||||||
throw new IllegalArgumentException("Two content objects cannot have the same name! (issue: '" + content.name + "')");
|
throw new IllegalArgumentException("Two content objects cannot have the same name! (issue: '" + content.name + "')");
|
||||||
}
|
}
|
||||||
if(currentMod != null){
|
if(currentMod != null){
|
||||||
content.mod = currentMod;
|
content.minfo.mod = currentMod;
|
||||||
}
|
}
|
||||||
contentNameMap[content.getContentType().ordinal()].put(content.name, content);
|
contentNameMap[content.getContentType().ordinal()].put(content.name, content);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,16 +7,18 @@ import io.anuke.arc.files.*;
|
|||||||
|
|
||||||
/** Handles files in a modded context. */
|
/** Handles files in a modded context. */
|
||||||
public class FileTree implements FileHandleResolver{
|
public class FileTree implements FileHandleResolver{
|
||||||
private ObjectMap<String, FileHandle> files = new ObjectMap<>();
|
private ObjectMap<String, Fi> files = new ObjectMap<>();
|
||||||
|
|
||||||
public void addFile(String path, FileHandle f){
|
public void addFile(String path, Fi f){
|
||||||
files.put(path, f);
|
files.put(path, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets an asset file.*/
|
/** Gets an asset file.*/
|
||||||
public FileHandle get(String path){
|
public Fi get(String path){
|
||||||
if(files.containsKey(path)){
|
if(files.containsKey(path)){
|
||||||
return files.get(path);
|
return files.get(path);
|
||||||
|
}else if(files.containsKey("/" + path)){
|
||||||
|
return files.get("/" + path);
|
||||||
}else{
|
}else{
|
||||||
return Core.files.internal(path);
|
return Core.files.internal(path);
|
||||||
}
|
}
|
||||||
@@ -28,7 +30,7 @@ public class FileTree implements FileHandleResolver{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle resolve(String fileName){
|
public Fi resolve(String fileName){
|
||||||
return get(fileName);
|
return get(fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import io.anuke.arc.util.io.*;
|
|||||||
import io.anuke.arc.util.serialization.*;
|
import io.anuke.arc.util.serialization.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.core.GameState.*;
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
@@ -22,7 +23,6 @@ import io.anuke.mindustry.net.Administration.*;
|
|||||||
import io.anuke.mindustry.net.Net.*;
|
import io.anuke.mindustry.net.Net.*;
|
||||||
import io.anuke.mindustry.net.*;
|
import io.anuke.mindustry.net.*;
|
||||||
import io.anuke.mindustry.net.Packets.*;
|
import io.anuke.mindustry.net.Packets.*;
|
||||||
import io.anuke.mindustry.type.*;
|
|
||||||
import io.anuke.mindustry.type.TypeID;
|
import io.anuke.mindustry.type.TypeID;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
import io.anuke.mindustry.world.modules.*;
|
import io.anuke.mindustry.world.modules.*;
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(){
|
public void init(){
|
||||||
mods.each(mod -> mod.registerClientCommands(clientCommands));
|
mods.eachClass(mod -> mod.registerClientCommands(clientCommands));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerCommands(){
|
private void registerCommands(){
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ public interface Platform{
|
|||||||
default void viewListingID(String mapid){}
|
default void viewListingID(String mapid){}
|
||||||
|
|
||||||
/** Steam: Return external workshop maps to be loaded.*/
|
/** Steam: Return external workshop maps to be loaded.*/
|
||||||
default Array<FileHandle> getWorkshopContent(Class<? extends Publishable> type){
|
default Array<Fi> getWorkshopContent(Class<? extends Publishable> type){
|
||||||
return new Array<>(0);
|
return new Array<>(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +100,7 @@ public interface Platform{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Only used for iOS or android: open the share menu for a map or save. */
|
/** Only used for iOS or android: open the share menu for a map or save. */
|
||||||
default void shareFile(FileHandle file){
|
default void shareFile(Fi file){
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +109,7 @@ public interface Platform{
|
|||||||
* @param open Whether to open or save files
|
* @param open Whether to open or save files
|
||||||
* @param extension File extension to filter
|
* @param extension File extension to filter
|
||||||
*/
|
*/
|
||||||
default void showFileChooser(boolean open, String extension, Cons<FileHandle> cons){
|
default void showFileChooser(boolean open, String extension, Cons<Fi> cons){
|
||||||
new FileChooser(open ? "$open" : "$save", file -> file.extension().toLowerCase().equals(extension), open, file -> {
|
new FileChooser(open ? "$open" : "$save", file -> file.extension().toLowerCase().equals(extension), open, file -> {
|
||||||
if(!open){
|
if(!open){
|
||||||
cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension));
|
cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension));
|
||||||
|
|||||||
@@ -456,7 +456,7 @@ public class Renderer implements ApplicationListener{
|
|||||||
buffer.end();
|
buffer.end();
|
||||||
Pixmap fullPixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);
|
Pixmap fullPixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);
|
||||||
BufferUtils.copy(lines, 0, fullPixmap.getPixels(), lines.length);
|
BufferUtils.copy(lines, 0, fullPixmap.getPixels(), lines.length);
|
||||||
FileHandle file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png");
|
Fi file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png");
|
||||||
PixmapIO.writePNG(file, fullPixmap);
|
PixmapIO.writePNG(file, fullPixmap);
|
||||||
fullPixmap.dispose();
|
fullPixmap.dispose();
|
||||||
ui.showInfoFade(Core.bundle.format("screenshot", file.toString()));
|
ui.showInfoFade(Core.bundle.format("screenshot", file.toString()));
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver));
|
Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver));
|
||||||
Core.assets.setLoader(BitmapFont.class, null, new FreetypeFontLoader(resolver){
|
Core.assets.setLoader(BitmapFont.class, null, new FreetypeFontLoader(resolver){
|
||||||
@Override
|
@Override
|
||||||
public BitmapFont loadSync(AssetManager manager, String fileName, FileHandle file, FreeTypeFontLoaderParameter parameter){
|
public BitmapFont loadSync(AssetManager manager, String fileName, Fi file, FreeTypeFontLoaderParameter parameter){
|
||||||
if(fileName.equals("outline")){
|
if(fileName.equals("outline")){
|
||||||
parameter.fontParameters.borderWidth = Scl.scl(2f);
|
parameter.fontParameters.borderWidth = Scl.scl(2f);
|
||||||
parameter.fontParameters.spaceX -= parameter.fontParameters.borderWidth;
|
parameter.fontParameters.spaceX -= parameter.fontParameters.borderWidth;
|
||||||
@@ -374,6 +374,37 @@ public class UI implements ApplicationListener, Loadable{
|
|||||||
}}.show();
|
}}.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void showExceptions(String text, String... messages){
|
||||||
|
loadfrag.hide();
|
||||||
|
new Dialog(""){{
|
||||||
|
|
||||||
|
setFillParent(true);
|
||||||
|
cont.margin(15);
|
||||||
|
cont.add("$error.title").colspan(2);
|
||||||
|
cont.row();
|
||||||
|
cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet);
|
||||||
|
cont.row();
|
||||||
|
cont.add(text).colspan(2).wrap().growX().center().get().setAlignment(Align.center);
|
||||||
|
cont.row();
|
||||||
|
|
||||||
|
//cont.pane(p -> {
|
||||||
|
for(int i = 0; i < messages.length; i += 2){
|
||||||
|
String btext = messages[i];
|
||||||
|
String details = messages[i + 1];
|
||||||
|
Collapser col = new Collapser(base -> base.pane(t -> t.margin(14f).add(details).color(Color.lightGray).left()), true);
|
||||||
|
|
||||||
|
cont.add(btext).right();
|
||||||
|
cont.addButton("$details", Styles.togglet, col::toggle).size(180f, 50f).checked(b -> !col.isCollapsed()).fillX().left();
|
||||||
|
cont.row();
|
||||||
|
cont.add(col).colspan(2).pad(2);
|
||||||
|
cont.row();
|
||||||
|
}
|
||||||
|
//}).colspan(2);
|
||||||
|
|
||||||
|
cont.addButton("$ok", this::hide).size(300, 50).fillX().colspan(2);
|
||||||
|
}}.show();
|
||||||
|
}
|
||||||
|
|
||||||
public void showText(String titleText, String text){
|
public void showText(String titleText, String text){
|
||||||
showText(titleText, text, Align.center);
|
showText(titleText, text, Align.center);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ import io.anuke.arc.files.*;
|
|||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.io.*;
|
import io.anuke.arc.util.io.*;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public class Version{
|
public class Version{
|
||||||
/** Build type. 'official' for official releases; 'custom' or 'bleeding edge' are also used. */
|
/** Build type. 'official' for official releases; 'custom' or 'bleeding edge' are also used. */
|
||||||
public static String type;
|
public static String type;
|
||||||
@@ -26,29 +24,25 @@ public class Version{
|
|||||||
public static void init(){
|
public static void init(){
|
||||||
if(!enabled) return;
|
if(!enabled) return;
|
||||||
|
|
||||||
try{
|
Fi file = OS.isAndroid || OS.isIos ? Core.files.internal("version.properties") : new Fi("version.properties", FileType.internal);
|
||||||
FileHandle file = OS.isAndroid || OS.isIos ? Core.files.internal("version.properties") : new FileHandle("version.properties", FileType.Internal);
|
|
||||||
|
|
||||||
ObjectMap<String, String> map = new ObjectMap<>();
|
ObjectMap<String, String> map = new ObjectMap<>();
|
||||||
PropertiesUtils.load(map, file.reader());
|
PropertiesUtils.load(map, file.reader());
|
||||||
|
|
||||||
type = map.get("type");
|
type = map.get("type");
|
||||||
number = Integer.parseInt(map.get("number", "4"));
|
number = Integer.parseInt(map.get("number", "4"));
|
||||||
modifier = map.get("modifier");
|
modifier = map.get("modifier");
|
||||||
if(map.get("build").contains(".")){
|
if(map.get("build").contains(".")){
|
||||||
String[] split = map.get("build").split("\\.");
|
String[] split = map.get("build").split("\\.");
|
||||||
try{
|
try{
|
||||||
build = Integer.parseInt(split[0]);
|
build = Integer.parseInt(split[0]);
|
||||||
revision = Integer.parseInt(split[1]);
|
revision = Integer.parseInt(split[1]);
|
||||||
}catch(Throwable e){
|
}catch(Throwable e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
build = -1;
|
build = -1;
|
||||||
}
|
|
||||||
}else{
|
|
||||||
build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
|
|
||||||
}
|
}
|
||||||
}catch(IOException e){
|
}else{
|
||||||
throw new RuntimeException(e);
|
build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,14 @@ import io.anuke.arc.files.*;
|
|||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.mod.Mods.*;
|
import io.anuke.mindustry.mod.Mods.*;
|
||||||
import io.anuke.mindustry.type.*;
|
|
||||||
|
|
||||||
|
|
||||||
/** Base class for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. */
|
/** Base class for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. */
|
||||||
public abstract class Content implements Comparable<Content>{
|
public abstract class Content implements Comparable<Content>{
|
||||||
public final short id;
|
public final short id;
|
||||||
/** The mod that loaded this piece of content. */
|
/** Info on which mod this content was loaded from. */
|
||||||
public @Nullable LoadedMod mod;
|
public @NonNull ModContentInfo minfo = new ModContentInfo();
|
||||||
/** File that this content was loaded from. */
|
|
||||||
public @Nullable FileHandle sourceFile;
|
|
||||||
|
|
||||||
public Content(){
|
public Content(){
|
||||||
this.id = (short)Vars.content.getBy(getContentType()).size;
|
this.id = (short)Vars.content.getBy(getContentType()).size;
|
||||||
@@ -37,6 +35,11 @@ public abstract class Content implements Comparable<Content>{
|
|||||||
public void load(){
|
public void load(){
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @return whether an error ocurred during mod loading. */
|
||||||
|
public boolean hasErrored(){
|
||||||
|
return minfo.error != null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(Content c){
|
public int compareTo(Content c){
|
||||||
return Integer.compare(id, c.id);
|
return Integer.compare(id, c.id);
|
||||||
@@ -46,4 +49,15 @@ public abstract class Content implements Comparable<Content>{
|
|||||||
public String toString(){
|
public String toString(){
|
||||||
return getContentType().name() + "#" + id;
|
return getContentType().name() + "#" + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ModContentInfo{
|
||||||
|
/** The mod that loaded this piece of content. */
|
||||||
|
public @Nullable LoadedMod mod;
|
||||||
|
/** File that this content was loaded from. */
|
||||||
|
public @Nullable Fi sourceFile;
|
||||||
|
/** The error that occurred during loading, if applicable. Null if no error occurred. */
|
||||||
|
public @Nullable String error;
|
||||||
|
/** Base throwable that caused the error. */
|
||||||
|
public @Nullable Throwable baseError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.anuke.mindustry.type;
|
package io.anuke.mindustry.ctype;
|
||||||
|
|
||||||
/** Do not rearrange, ever! */
|
/** Do not rearrange, ever! */
|
||||||
public enum ContentType{
|
public enum ContentType{
|
||||||
@@ -13,7 +13,8 @@ public enum ContentType{
|
|||||||
effect,
|
effect,
|
||||||
zone,
|
zone,
|
||||||
loadout,
|
loadout,
|
||||||
typeid;
|
typeid,
|
||||||
|
error;
|
||||||
|
|
||||||
public static final ContentType[] all = values();
|
public static final ContentType[] all = values();
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.arc.collection.StringMap;
|
import io.anuke.arc.collection.StringMap;
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.Fi;
|
||||||
import io.anuke.arc.func.Cons;
|
import io.anuke.arc.func.Cons;
|
||||||
import io.anuke.arc.func.Boolf;
|
import io.anuke.arc.func.Boolf;
|
||||||
import io.anuke.arc.graphics.Pixmap;
|
import io.anuke.arc.graphics.Pixmap;
|
||||||
@@ -109,7 +109,7 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map createMap(FileHandle file){
|
public Map createMap(Fi file){
|
||||||
return new Map(file, width(), height(), new StringMap(tags), true);
|
return new Map(file, width(), height(), new StringMap(tags), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
}else{
|
}else{
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
FileHandle result = Core.files.local(editor.getTags().get("name", "unknown") + "." + mapExtension);
|
Fi result = Core.files.local(editor.getTags().get("name", "unknown") + "." + mapExtension);
|
||||||
MapIO.writeMap(result, editor.createMap(result));
|
MapIO.writeMap(result, editor.createMap(result));
|
||||||
platform.shareFile(result);
|
platform.shareFile(result);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -381,7 +381,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
editor.renderer().dispose();
|
editor.renderer().dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beginEditMap(FileHandle file){
|
public void beginEditMap(Fi file){
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
shownWithMap = true;
|
shownWithMap = true;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import io.anuke.arc.scene.ui.layout.*;
|
|||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import io.anuke.arc.audio.*;
|
|||||||
import io.anuke.arc.math.*;
|
import io.anuke.arc.math.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.ctype.Content;
|
import io.anuke.mindustry.ctype.Content;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.Effects.*;
|
import io.anuke.mindustry.entities.Effects.*;
|
||||||
import io.anuke.mindustry.entities.effect.*;
|
import io.anuke.mindustry.entities.effect.*;
|
||||||
@@ -137,7 +138,7 @@ public abstract class BulletType extends Content{
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < lightining; i++){
|
for(int i = 0; i < lightining; i++){
|
||||||
Lightning.create(b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
Lightning.createLighting(Lightning.nextSeed(), b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +151,7 @@ public abstract class BulletType extends Content{
|
|||||||
public void update(Bullet b){
|
public void update(Bullet b){
|
||||||
|
|
||||||
if(homingPower > 0.0001f){
|
if(homingPower > 0.0001f){
|
||||||
TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange);
|
TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange, e -> !e.isFlying() || collidesAir);
|
||||||
if(target != null){
|
if(target != null){
|
||||||
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
|
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,11 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{
|
|||||||
|
|
||||||
/** Create a lighting branch at a location. Use Team.none to damage everyone. */
|
/** Create a lighting branch at a location. Use Team.none to damage everyone. */
|
||||||
public static void create(Team team, Color color, float damage, float x, float y, float targetAngle, int length){
|
public static void create(Team team, Color color, float damage, float x, float y, float targetAngle, int length){
|
||||||
Call.createLighting(lastSeed++, team, color, damage, x, y, targetAngle, length);
|
Call.createLighting(nextSeed(), team, color, damage, x, y, targetAngle, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int nextSeed(){
|
||||||
|
return lastSeed++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Do not invoke! */
|
/** Do not invoke! */
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.anuke.arc.util.*;
|
|||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
import io.anuke.mindustry.entities.units.*;
|
import io.anuke.mindustry.entities.units.*;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import io.anuke.arc.util.pooling.*;
|
|||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import io.anuke.arc.graphics.*;
|
|||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.pooling.*;
|
import io.anuke.arc.util.pooling.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
|
|||||||
@@ -139,9 +139,19 @@ public class EventType{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a player withdraws items from a block. Tutorial only.*/
|
/** Called when the player withdraws items from a block. */
|
||||||
public static class WithdrawEvent{
|
public static class WithdrawEvent{
|
||||||
|
public final Tile tile;
|
||||||
|
public final Player player;
|
||||||
|
public final Item item;
|
||||||
|
public final int amount;
|
||||||
|
|
||||||
|
public WithdrawEvent(Tile tile, Player player, Item item, int amount){
|
||||||
|
this.tile = tile;
|
||||||
|
this.player = player;
|
||||||
|
this.item = item;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when a player deposits items to a block.*/
|
/** Called when a player deposits items to a block.*/
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import io.anuke.arc.files.*;
|
|||||||
import io.anuke.arc.util.io.*;
|
import io.anuke.arc.util.io.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
import io.anuke.mindustry.ctype.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@ public class GlobalData{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exportData(FileHandle file) throws IOException{
|
public void exportData(Fi file) throws IOException{
|
||||||
Array<FileHandle> files = new Array<>();
|
Array<Fi> files = new Array<>();
|
||||||
files.add(Core.settings.getSettingsFile());
|
files.add(Core.settings.getSettingsFile());
|
||||||
files.addAll(customMapDirectory.list());
|
files.addAll(customMapDirectory.list());
|
||||||
files.addAll(saveDirectory.list());
|
files.addAll(saveDirectory.list());
|
||||||
@@ -46,7 +46,7 @@ public class GlobalData{
|
|||||||
String base = Core.settings.getDataDirectory().path();
|
String base = Core.settings.getDataDirectory().path();
|
||||||
|
|
||||||
try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){
|
try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){
|
||||||
for(FileHandle add : files){
|
for(Fi add : files){
|
||||||
if(add.isDirectory()) continue;
|
if(add.isDirectory()) continue;
|
||||||
zos.putNextEntry(new ZipEntry(add.path().substring(base.length())));
|
zos.putNextEntry(new ZipEntry(add.path().substring(base.length())));
|
||||||
Streams.copyStream(add.read(), zos);
|
Streams.copyStream(add.read(), zos);
|
||||||
@@ -56,12 +56,12 @@ public class GlobalData{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importData(FileHandle file){
|
public void importData(Fi file){
|
||||||
FileHandle dest = Core.files.local("zipdata.zip");
|
Fi dest = Core.files.local("zipdata.zip");
|
||||||
file.copyTo(dest);
|
file.copyTo(dest);
|
||||||
FileHandle zipped = new ZipFileHandle(dest);
|
Fi zipped = new ZipFi(dest);
|
||||||
|
|
||||||
FileHandle base = Core.settings.getDataDirectory();
|
Fi base = Core.settings.getDataDirectory();
|
||||||
if(!zipped.child("settings.bin").exists()){
|
if(!zipped.child("settings.bin").exists()){
|
||||||
throw new IllegalArgumentException("Not valid save data.");
|
throw new IllegalArgumentException("Not valid save data.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class Saves{
|
|||||||
private AsyncExecutor previewExecutor = new AsyncExecutor(1);
|
private AsyncExecutor previewExecutor = new AsyncExecutor(1);
|
||||||
private boolean saving;
|
private boolean saving;
|
||||||
private float time;
|
private float time;
|
||||||
private FileHandle zoneFile;
|
private Fi zoneFile;
|
||||||
|
|
||||||
private long totalPlaytime;
|
private long totalPlaytime;
|
||||||
private long lastTimestamp;
|
private long lastTimestamp;
|
||||||
@@ -48,7 +48,7 @@ public class Saves{
|
|||||||
saves.clear();
|
saves.clear();
|
||||||
zoneFile = saveDirectory.child("-1.msav");
|
zoneFile = saveDirectory.child("-1.msav");
|
||||||
|
|
||||||
for(FileHandle file : saveDirectory.list()){
|
for(Fi file : saveDirectory.list()){
|
||||||
if(!file.name().contains("backup") && SaveIO.isSaveValid(file)){
|
if(!file.name().contains("backup") && SaveIO.isSaveValid(file)){
|
||||||
SaveSlot slot = new SaveSlot(file);
|
SaveSlot slot = new SaveSlot(file);
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
@@ -121,7 +121,7 @@ public class Saves{
|
|||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SaveSlot importSave(FileHandle file) throws IOException{
|
public SaveSlot importSave(Fi file) throws IOException{
|
||||||
SaveSlot slot = new SaveSlot(getNextSlotFile());
|
SaveSlot slot = new SaveSlot(getNextSlotFile());
|
||||||
slot.importFile(file);
|
slot.importFile(file);
|
||||||
slot.setName(file.nameWithoutExtension());
|
slot.setName(file.nameWithoutExtension());
|
||||||
@@ -136,9 +136,9 @@ public class Saves{
|
|||||||
return slot == null || slot.getZone() == null ? null : slot;
|
return slot == null || slot.getZone() == null ? null : slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileHandle getNextSlotFile(){
|
public Fi getNextSlotFile(){
|
||||||
int i = 0;
|
int i = 0;
|
||||||
FileHandle file;
|
Fi file;
|
||||||
while((file = saveDirectory.child(i + "." + saveExtension)).exists()){
|
while((file = saveDirectory.child(i + "." + saveExtension)).exists()){
|
||||||
i ++;
|
i ++;
|
||||||
}
|
}
|
||||||
@@ -151,11 +151,11 @@ public class Saves{
|
|||||||
|
|
||||||
public class SaveSlot{
|
public class SaveSlot{
|
||||||
//public final int index;
|
//public final int index;
|
||||||
public final FileHandle file;
|
public final Fi file;
|
||||||
boolean requestedPreview;
|
boolean requestedPreview;
|
||||||
SaveMeta meta;
|
SaveMeta meta;
|
||||||
|
|
||||||
public SaveSlot(FileHandle file){
|
public SaveSlot(Fi file){
|
||||||
this.file = file;
|
this.file = file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,11 +216,11 @@ public class Saves{
|
|||||||
return file.nameWithoutExtension();
|
return file.nameWithoutExtension();
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileHandle previewFile(){
|
private Fi previewFile(){
|
||||||
return mapPreviewDirectory.child("save_slot_" + index() + ".png");
|
return mapPreviewDirectory.child("save_slot_" + index() + ".png");
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileHandle loadPreviewFile(){
|
private Fi loadPreviewFile(){
|
||||||
return previewFile().sibling(previewFile().name() + ".spreview");
|
return previewFile().sibling(previewFile().name() + ".spreview");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,7 +293,7 @@ public class Saves{
|
|||||||
Core.settings.save();
|
Core.settings.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void importFile(FileHandle from) throws IOException{
|
public void importFile(Fi from) throws IOException{
|
||||||
try{
|
try{
|
||||||
from.copyTo(file);
|
from.copyTo(file);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -301,7 +301,7 @@ public class Saves{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void exportFile(FileHandle to) throws IOException{
|
public void exportFile(Fi to) throws IOException{
|
||||||
try{
|
try{
|
||||||
file.copyTo(to);
|
file.copyTo(to);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ public class Schematic implements Publishable, Comparable<Schematic>{
|
|||||||
public final Array<Stile> tiles;
|
public final Array<Stile> tiles;
|
||||||
public StringMap tags;
|
public StringMap tags;
|
||||||
public int width, height;
|
public int width, height;
|
||||||
public @Nullable FileHandle file;
|
public @Nullable
|
||||||
|
Fi file;
|
||||||
/** Associated mod. If null, no mod is associated with this schematic. */
|
/** Associated mod. If null, no mod is associated with this schematic. */
|
||||||
public @Nullable LoadedMod mod;
|
public @Nullable LoadedMod mod;
|
||||||
|
|
||||||
@@ -94,15 +95,15 @@ public class Schematic implements Publishable, Comparable<Schematic>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle createSteamFolder(String id){
|
public Fi createSteamFolder(String id){
|
||||||
FileHandle directory = tmpDirectory.child("schematic_" + id).child("schematic." + schematicExtension);
|
Fi directory = tmpDirectory.child("schematic_" + id).child("schematic." + schematicExtension);
|
||||||
file.copyTo(directory);
|
file.copyTo(directory);
|
||||||
return directory;
|
return directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle createSteamPreview(String id){
|
public Fi createSteamPreview(String id){
|
||||||
FileHandle preview = tmpDirectory.child("schematic_preview_" + id + ".png");
|
Fi preview = tmpDirectory.child("schematic_preview_" + id + ".png");
|
||||||
schematics.savePreview(this, preview);
|
schematics.savePreview(this, preview);
|
||||||
return preview;
|
return preview;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import io.anuke.arc.util.io.Streams.*;
|
|||||||
import io.anuke.arc.util.serialization.*;
|
import io.anuke.arc.util.serialization.*;
|
||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.game.Schematic.*;
|
import io.anuke.mindustry.game.Schematic.*;
|
||||||
import io.anuke.mindustry.input.*;
|
import io.anuke.mindustry.input.*;
|
||||||
import io.anuke.mindustry.input.Placement.*;
|
import io.anuke.mindustry.input.Placement.*;
|
||||||
import io.anuke.mindustry.type.*;
|
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
import io.anuke.mindustry.world.blocks.*;
|
import io.anuke.mindustry.world.blocks.*;
|
||||||
import io.anuke.mindustry.world.blocks.production.*;
|
import io.anuke.mindustry.world.blocks.production.*;
|
||||||
@@ -69,7 +69,7 @@ public class Schematics implements Loadable{
|
|||||||
public void load(){
|
public void load(){
|
||||||
all.clear();
|
all.clear();
|
||||||
|
|
||||||
for(FileHandle file : schematicDirectory.list()){
|
for(Fi file : schematicDirectory.list()){
|
||||||
loadFile(file);
|
loadFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ public class Schematics implements Loadable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private @Nullable Schematic loadFile(FileHandle file){
|
private @Nullable Schematic loadFile(Fi file){
|
||||||
if(!file.extension().equals(schematicExtension)) return null;
|
if(!file.extension().equals(schematicExtension)) return null;
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@@ -144,7 +144,7 @@ public class Schematics implements Loadable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void savePreview(Schematic schematic, FileHandle file){
|
public void savePreview(Schematic schematic, Fi file){
|
||||||
FrameBuffer buffer = getBuffer(schematic);
|
FrameBuffer buffer = getBuffer(schematic);
|
||||||
Draw.flush();
|
Draw.flush();
|
||||||
buffer.begin();
|
buffer.begin();
|
||||||
@@ -272,7 +272,7 @@ public class Schematics implements Loadable{
|
|||||||
public void add(Schematic schematic){
|
public void add(Schematic schematic){
|
||||||
all.add(schematic);
|
all.add(schematic);
|
||||||
try{
|
try{
|
||||||
FileHandle file = schematicDirectory.child(Time.millis() + "." + schematicExtension);
|
Fi file = schematicDirectory.child(Time.millis() + "." + schematicExtension);
|
||||||
write(schematic, file);
|
write(schematic, file);
|
||||||
schematic.file = file;
|
schematic.file = file;
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -372,7 +372,7 @@ public class Schematics implements Loadable{
|
|||||||
return read(new ByteArrayInputStream(Base64Coder.decode(schematic)));
|
return read(new ByteArrayInputStream(Base64Coder.decode(schematic)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Schematic read(FileHandle file) throws IOException{
|
public static Schematic read(Fi file) throws IOException{
|
||||||
Schematic s = read(new DataInputStream(file.read(1024)));
|
Schematic s = read(new DataInputStream(file.read(1024)));
|
||||||
if(!s.tags.containsKey("name")){
|
if(!s.tags.containsKey("name")){
|
||||||
s.tags.put("name", file.nameWithoutExtension());
|
s.tags.put("name", file.nameWithoutExtension());
|
||||||
@@ -425,7 +425,7 @@ public class Schematics implements Loadable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(Schematic schematic, FileHandle file) throws IOException{
|
public static void write(Schematic schematic, Fi file) throws IOException{
|
||||||
write(schematic, file.write(false, 1024));
|
write(schematic, file.write(false, 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import io.anuke.arc.util.serialization.Json;
|
|||||||
import io.anuke.arc.util.serialization.Json.Serializable;
|
import io.anuke.arc.util.serialization.Json.Serializable;
|
||||||
import io.anuke.arc.util.serialization.JsonValue;
|
import io.anuke.arc.util.serialization.JsonValue;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
|
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ public enum Binding implements KeyBind{
|
|||||||
block_select_08(KeyCode.NUM_8),
|
block_select_08(KeyCode.NUM_8),
|
||||||
block_select_09(KeyCode.NUM_9),
|
block_select_09(KeyCode.NUM_9),
|
||||||
block_select_10(KeyCode.NUM_0),
|
block_select_10(KeyCode.NUM_0),
|
||||||
zoom_hold(KeyCode.CONTROL_LEFT, "view"),
|
zoom(new Axis(KeyCode.SCROLL), "view"),
|
||||||
zoom(new Axis(KeyCode.SCROLL)),
|
|
||||||
menu(Core.app.getType() == ApplicationType.Android ? KeyCode.BACK : KeyCode.ESCAPE),
|
menu(Core.app.getType() == ApplicationType.Android ? KeyCode.BACK : KeyCode.ESCAPE),
|
||||||
fullscreen(KeyCode.F11),
|
fullscreen(KeyCode.F11),
|
||||||
pause(KeyCode.SPACE),
|
pause(KeyCode.SPACE),
|
||||||
|
|||||||
@@ -149,8 +149,8 @@ public class DesktopInput extends InputHandler{
|
|||||||
|
|
||||||
if(state.is(State.menu) || Core.scene.hasDialog()) return;
|
if(state.is(State.menu) || Core.scene.hasDialog()) return;
|
||||||
|
|
||||||
//zoom things
|
//zoom camera
|
||||||
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && Core.input.keyDown(Binding.zoom_hold)){
|
if(!Core.scene.hasScroll() && Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && !Core.input.keyDown(Binding.rotateplaced) && (Core.input.keyDown(Binding.diagonal_placement) || ((!isPlacing() || !block.rotate) && selectRequests.isEmpty()))){
|
||||||
renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
|
renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,11 +166,6 @@ public class DesktopInput extends InputHandler{
|
|||||||
mode = none;
|
mode = none;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mode != none || isPlacing()){
|
|
||||||
selectRequests.clear();
|
|
||||||
lastSchematic = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(player.isShooting && !canShoot()){
|
if(player.isShooting && !canShoot()){
|
||||||
player.isShooting = false;
|
player.isShooting = false;
|
||||||
}
|
}
|
||||||
@@ -182,8 +177,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
selectScale = 0f;
|
selectScale = 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Core.input.keyDown(Binding.zoom_hold) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){
|
if(!Core.input.keyDown(Binding.diagonal_placement) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){
|
||||||
|
|
||||||
rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4);
|
rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4);
|
||||||
|
|
||||||
if(sreq != null){
|
if(sreq != null){
|
||||||
@@ -355,7 +349,9 @@ public class DesktopInput extends InputHandler{
|
|||||||
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
|
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
|
||||||
BuildRequest req = getRequest(cursorX, cursorY);
|
BuildRequest req = getRequest(cursorX, cursorY);
|
||||||
|
|
||||||
if(!selectRequests.isEmpty()){
|
if(Core.input.keyDown(Binding.break_block)){
|
||||||
|
mode = none;
|
||||||
|
}else if(!selectRequests.isEmpty()){
|
||||||
flushRequests(selectRequests);
|
flushRequests(selectRequests);
|
||||||
}else if(isPlacing()){
|
}else if(isPlacing()){
|
||||||
selectX = cursorX;
|
selectX = cursorX;
|
||||||
@@ -377,9 +373,12 @@ public class DesktopInput extends InputHandler{
|
|||||||
}else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine
|
}else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine
|
||||||
player.isShooting = true;
|
player.isShooting = true;
|
||||||
}
|
}
|
||||||
}else if(Core.input.keyTap(Binding.deselect) && block != null){
|
}else if(Core.input.keyTap(Binding.deselect) && isPlacing()){
|
||||||
block = null;
|
block = null;
|
||||||
mode = none;
|
mode = none;
|
||||||
|
}else if(Core.input.keyTap(Binding.deselect) && !selectRequests.isEmpty()){
|
||||||
|
selectRequests.clear();
|
||||||
|
lastSchematic = null;
|
||||||
}else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){
|
}else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){
|
||||||
//is recalculated because setting the mode to breaking removes potential multiblock cursor offset
|
//is recalculated because setting the mode to breaking removes potential multiblock cursor offset
|
||||||
deleting = false;
|
deleting = false;
|
||||||
|
|||||||
@@ -587,8 +587,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
mode = none;
|
mode = none;
|
||||||
}
|
}
|
||||||
|
|
||||||
//zoom things
|
//zoom camera
|
||||||
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && (Core.input.keyDown(Binding.zoom_hold))){
|
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && !Core.input.keyDown(Binding.rotateplaced) && (Core.input.keyDown(Binding.diagonal_placement) || ((!isPlacing() || !block.rotate) && selectRequests.isEmpty()))){
|
||||||
renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
|
renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import io.anuke.arc.util.serialization.Json.*;
|
|||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import io.anuke.arc.graphics.*;
|
|||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.serialization.*;
|
import io.anuke.arc.util.serialization.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
import io.anuke.mindustry.io.MapIO.*;
|
import io.anuke.mindustry.io.MapIO.*;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
import io.anuke.mindustry.type.*;
|
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
import io.anuke.mindustry.world.LegacyColorMapper.*;
|
import io.anuke.mindustry.world.LegacyColorMapper.*;
|
||||||
import io.anuke.mindustry.world.blocks.*;
|
import io.anuke.mindustry.world.blocks.*;
|
||||||
@@ -26,7 +26,7 @@ public class LegacyMapIO{
|
|||||||
private static final Json json = new Json();
|
private static final Json json = new Json();
|
||||||
|
|
||||||
/* Convert a map from the old format to the new format. */
|
/* Convert a map from the old format to the new format. */
|
||||||
public static void convertMap(FileHandle in, FileHandle out) throws IOException{
|
public static void convertMap(Fi in, Fi out) throws IOException{
|
||||||
Map map = readMap(in, true);
|
Map map = readMap(in, true);
|
||||||
|
|
||||||
String waves = map.tags.get("waves", "[]");
|
String waves = map.tags.get("waves", "[]");
|
||||||
@@ -45,7 +45,7 @@ public class LegacyMapIO{
|
|||||||
MapIO.writeMap(out, map);
|
MapIO.writeMap(out, map);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map readMap(FileHandle file, boolean custom) throws IOException{
|
public static Map readMap(Fi file, boolean custom) throws IOException{
|
||||||
try(DataInputStream stream = new DataInputStream(file.read(1024))){
|
try(DataInputStream stream = new DataInputStream(file.read(1024))){
|
||||||
StringMap tags = new StringMap();
|
StringMap tags = new StringMap();
|
||||||
|
|
||||||
@@ -76,11 +76,11 @@ public class LegacyMapIO{
|
|||||||
readTiles(map.file, map.width, map.height, tiles);
|
readTiles(map.file, map.width, map.height, tiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{
|
private static void readTiles(Fi file, int width, int height, Tile[][] tiles) throws IOException{
|
||||||
readTiles(file, width, height, (x, y) -> tiles[x][y]);
|
readTiles(file, width, height, (x, y) -> tiles[x][y]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void readTiles(FileHandle file, int width, int height, TileProvider tiles) throws IOException{
|
private static void readTiles(Fi file, int width, int height, TileProvider tiles) throws IOException{
|
||||||
try(BufferedInputStream input = file.read(bufferSize)){
|
try(BufferedInputStream input = file.read(bufferSize)){
|
||||||
|
|
||||||
//read map
|
//read map
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import static io.anuke.mindustry.Vars.*;
|
|||||||
public class MapIO{
|
public class MapIO{
|
||||||
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
|
||||||
|
|
||||||
public static boolean isImage(FileHandle file){
|
public static boolean isImage(Fi file){
|
||||||
try(InputStream stream = file.read(32)){
|
try(InputStream stream = file.read(32)){
|
||||||
for(int i1 : pngHeader){
|
for(int i1 : pngHeader){
|
||||||
if(stream.read() != i1){
|
if(stream.read() != i1){
|
||||||
@@ -35,7 +35,7 @@ public class MapIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map createMap(FileHandle file, boolean custom) throws IOException{
|
public static Map createMap(Fi file, boolean custom) throws IOException{
|
||||||
try(InputStream is = new InflaterInputStream(file.read(bufferSize)); CounterInputStream counter = new CounterInputStream(is); DataInputStream stream = new DataInputStream(counter)){
|
try(InputStream is = new InflaterInputStream(file.read(bufferSize)); CounterInputStream counter = new CounterInputStream(is); DataInputStream stream = new DataInputStream(counter)){
|
||||||
SaveIO.readHeader(stream);
|
SaveIO.readHeader(stream);
|
||||||
int version = stream.readInt();
|
int version = stream.readInt();
|
||||||
@@ -46,7 +46,7 @@ public class MapIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writeMap(FileHandle file, Map map) throws IOException{
|
public static void writeMap(Fi file, Map map) throws IOException{
|
||||||
try{
|
try{
|
||||||
SaveIO.write(file, map.tags);
|
SaveIO.write(file, map.tags);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package io.anuke.mindustry.io;
|
package io.anuke.mindustry.io;
|
||||||
|
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.Fi;
|
||||||
import io.anuke.arc.util.io.CounterInputStream;
|
import io.anuke.arc.util.io.CounterInputStream;
|
||||||
import io.anuke.arc.util.io.FastDeflaterOutputStream;
|
import io.anuke.arc.util.io.FastDeflaterOutputStream;
|
||||||
import io.anuke.mindustry.Vars;
|
import io.anuke.mindustry.Vars;
|
||||||
@@ -34,7 +34,7 @@ public class SaveIO{
|
|||||||
return versions.get(version);
|
return versions.get(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void save(FileHandle file){
|
public static void save(Fi file){
|
||||||
boolean exists = file.exists();
|
boolean exists = file.exists();
|
||||||
if(exists) file.moveTo(backupFileFor(file));
|
if(exists) file.moveTo(backupFileFor(file));
|
||||||
try{
|
try{
|
||||||
@@ -45,15 +45,15 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataInputStream getStream(FileHandle file){
|
public static DataInputStream getStream(Fi file){
|
||||||
return new DataInputStream(new InflaterInputStream(file.read(bufferSize)));
|
return new DataInputStream(new InflaterInputStream(file.read(bufferSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DataInputStream getBackupStream(FileHandle file){
|
public static DataInputStream getBackupStream(Fi file){
|
||||||
return new DataInputStream(new InflaterInputStream(backupFileFor(file).read(bufferSize)));
|
return new DataInputStream(new InflaterInputStream(backupFileFor(file).read(bufferSize)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSaveValid(FileHandle file){
|
public static boolean isSaveValid(Fi file){
|
||||||
try{
|
try{
|
||||||
return isSaveValid(new DataInputStream(new InflaterInputStream(file.read(bufferSize))));
|
return isSaveValid(new DataInputStream(new InflaterInputStream(file.read(bufferSize))));
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -71,7 +71,7 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SaveMeta getMeta(FileHandle file){
|
public static SaveMeta getMeta(Fi file){
|
||||||
try{
|
try{
|
||||||
return getMeta(getStream(file));
|
return getMeta(getStream(file));
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -92,19 +92,19 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileHandle fileFor(int slot){
|
public static Fi fileFor(int slot){
|
||||||
return saveDirectory.child(slot + "." + Vars.saveExtension);
|
return saveDirectory.child(slot + "." + Vars.saveExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FileHandle backupFileFor(FileHandle file){
|
public static Fi backupFileFor(Fi file){
|
||||||
return file.sibling(file.name() + "-backup." + file.extension());
|
return file.sibling(file.name() + "-backup." + file.extension());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(FileHandle file, StringMap tags){
|
public static void write(Fi file, StringMap tags){
|
||||||
write(new FastDeflaterOutputStream(file.write(false, bufferSize)), tags);
|
write(new FastDeflaterOutputStream(file.write(false, bufferSize)), tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void write(FileHandle file){
|
public static void write(Fi file){
|
||||||
write(file, null);
|
write(file, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,17 +122,17 @@ public class SaveIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void load(FileHandle file) throws SaveException{
|
public static void load(Fi file) throws SaveException{
|
||||||
load(file, world.context);
|
load(file, world.context);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void load(FileHandle file, WorldContext context) throws SaveException{
|
public static void load(Fi file, WorldContext context) throws SaveException{
|
||||||
try{
|
try{
|
||||||
//try and load; if any exception at all occurs
|
//try and load; if any exception at all occurs
|
||||||
load(new InflaterInputStream(file.read(bufferSize)), context);
|
load(new InflaterInputStream(file.read(bufferSize)), context);
|
||||||
}catch(SaveException e){
|
}catch(SaveException e){
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
FileHandle backup = file.sibling(file.name() + "-backup." + file.extension());
|
Fi backup = file.sibling(file.name() + "-backup." + file.extension());
|
||||||
if(backup.exists()){
|
if(backup.exists()){
|
||||||
load(new InflaterInputStream(backup.read(bufferSize)), context);
|
load(new InflaterInputStream(backup.read(bufferSize)), context);
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ public class SavePreviewLoader extends TextureLoader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadAsync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){
|
public void loadAsync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){
|
||||||
try{
|
try{
|
||||||
super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter);
|
super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import io.anuke.arc.util.io.*;
|
|||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry.io;
|
|||||||
import io.anuke.annotations.Annotations.ReadClass;
|
import io.anuke.annotations.Annotations.ReadClass;
|
||||||
import io.anuke.annotations.Annotations.WriteClass;
|
import io.anuke.annotations.Annotations.WriteClass;
|
||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.Effects;
|
import io.anuke.mindustry.entities.Effects;
|
||||||
import io.anuke.mindustry.entities.Effects.Effect;
|
import io.anuke.mindustry.entities.Effects.Effect;
|
||||||
import io.anuke.mindustry.entities.type.Bullet;
|
import io.anuke.mindustry.entities.type.Bullet;
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package io.anuke.mindustry.io.versions;
|
package io.anuke.mindustry.io.versions;
|
||||||
|
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
import io.anuke.mindustry.io.*;
|
import io.anuke.mindustry.io.*;
|
||||||
import io.anuke.mindustry.type.*;
|
|
||||||
import io.anuke.mindustry.type.TypeID;
|
import io.anuke.mindustry.type.TypeID;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public class Map implements Comparable<Map>, Publishable{
|
|||||||
/** Metadata. Author description, display name, etc. */
|
/** Metadata. Author description, display name, etc. */
|
||||||
public final StringMap tags;
|
public final StringMap tags;
|
||||||
/** Base file of this map. File can be named anything at all. */
|
/** Base file of this map. File can be named anything at all. */
|
||||||
public final FileHandle file;
|
public final Fi file;
|
||||||
/** Format version. */
|
/** Format version. */
|
||||||
public final int version;
|
public final int version;
|
||||||
/** Whether this map is managed, e.g. downloaded from the Steam workshop.*/
|
/** Whether this map is managed, e.g. downloaded from the Steam workshop.*/
|
||||||
@@ -40,7 +40,7 @@ public class Map implements Comparable<Map>, Publishable{
|
|||||||
/** Associated mod. If null, no mod is associated. */
|
/** Associated mod. If null, no mod is associated. */
|
||||||
public @Nullable LoadedMod mod;
|
public @Nullable LoadedMod mod;
|
||||||
|
|
||||||
public Map(FileHandle file, int width, int height, StringMap tags, boolean custom, int version, int build){
|
public Map(Fi file, int width, int height, StringMap tags, boolean custom, int version, int build){
|
||||||
this.custom = custom;
|
this.custom = custom;
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
@@ -50,11 +50,11 @@ public class Map implements Comparable<Map>, Publishable{
|
|||||||
this.build = build;
|
this.build = build;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map(FileHandle file, int width, int height, StringMap tags, boolean custom, int version){
|
public Map(Fi file, int width, int height, StringMap tags, boolean custom, int version){
|
||||||
this(file, width, height, tags, custom, version, -1);
|
this(file, width, height, tags, custom, version, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map(FileHandle file, int width, int height, StringMap tags, boolean custom){
|
public Map(Fi file, int width, int height, StringMap tags, boolean custom){
|
||||||
this(file, width, height, tags, custom, -1);
|
this(file, width, height, tags, custom, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +70,11 @@ public class Map implements Comparable<Map>, Publishable{
|
|||||||
return texture == null ? Core.assets.get("sprites/error.png") : texture;
|
return texture == null ? Core.assets.get("sprites/error.png") : texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileHandle previewFile(){
|
public Fi previewFile(){
|
||||||
return Vars.mapPreviewDirectory.child((workshop ? file.parent().name() : file.nameWithoutExtension()) + ".png");
|
return Vars.mapPreviewDirectory.child((workshop ? file.parent().name() : file.nameWithoutExtension()) + ".png");
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileHandle cacheFile(){
|
public Fi cacheFile(){
|
||||||
return Vars.mapPreviewDirectory.child(workshop ? file.parent().name() + "-workshop-cache.dat" : file.nameWithoutExtension() + "-cache.dat");
|
return Vars.mapPreviewDirectory.child(workshop ? file.parent().name() + "-workshop-cache.dat" : file.nameWithoutExtension() + "-cache.dat");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,14 +184,14 @@ public class Map implements Comparable<Map>, Publishable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle createSteamFolder(String id){
|
public Fi createSteamFolder(String id){
|
||||||
FileHandle mapFile = tmpDirectory.child("map_" + id).child("map.msav");
|
Fi mapFile = tmpDirectory.child("map_" + id).child("map.msav");
|
||||||
file.copyTo(mapFile);
|
file.copyTo(mapFile);
|
||||||
return mapFile.parent();
|
return mapFile.parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle createSteamPreview(String id){
|
public Fi createSteamPreview(String id){
|
||||||
return previewFile();
|
return previewFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class MapPreviewLoader extends TextureLoader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void loadAsync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){
|
public void loadAsync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){
|
||||||
try{
|
try{
|
||||||
super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter);
|
super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -28,7 +28,7 @@ public class MapPreviewLoader extends TextureLoader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Texture loadSync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){
|
public Texture loadSync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){
|
||||||
try{
|
try{
|
||||||
return super.loadSync(manager, fileName, file, parameter);
|
return super.loadSync(manager, fileName, file, parameter);
|
||||||
}catch(Throwable e){
|
}catch(Throwable e){
|
||||||
@@ -43,7 +43,7 @@ public class MapPreviewLoader extends TextureLoader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Array<AssetDescriptor> getDependencies(String fileName, FileHandle file, TextureParameter parameter){
|
public Array<AssetDescriptor> getDependencies(String fileName, Fi file, TextureParameter parameter){
|
||||||
return Array.with(new AssetDescriptor<>("contentcreate", Content.class));
|
return Array.with(new AssetDescriptor<>("contentcreate", Content.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ public class Maps{
|
|||||||
* Does not add this map to the map list.
|
* Does not add this map to the map list.
|
||||||
*/
|
*/
|
||||||
public Map loadInternalMap(String name){
|
public Map loadInternalMap(String name){
|
||||||
FileHandle file = tree.get("maps/" + name + "." + mapExtension);
|
Fi file = tree.get("maps/" + name + "." + mapExtension);
|
||||||
|
|
||||||
try{
|
try{
|
||||||
return MapIO.createMap(file, false);
|
return MapIO.createMap(file, false);
|
||||||
@@ -119,7 +119,7 @@ public class Maps{
|
|||||||
//defaults; must work
|
//defaults; must work
|
||||||
try{
|
try{
|
||||||
for(String name : defaultMapNames){
|
for(String name : defaultMapNames){
|
||||||
FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension);
|
Fi file = Core.files.internal("maps/" + name + "." + mapExtension);
|
||||||
loadMap(file, false);
|
loadMap(file, false);
|
||||||
}
|
}
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
@@ -127,7 +127,7 @@ public class Maps{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//custom
|
//custom
|
||||||
for(FileHandle file : customMapDirectory.list()){
|
for(Fi file : customMapDirectory.list()){
|
||||||
try{
|
try{
|
||||||
if(file.extension().equalsIgnoreCase(mapExtension)){
|
if(file.extension().equalsIgnoreCase(mapExtension)){
|
||||||
loadMap(file, true);
|
loadMap(file, true);
|
||||||
@@ -139,7 +139,7 @@ public class Maps{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//workshop
|
//workshop
|
||||||
for(FileHandle file : platform.getWorkshopContent(Map.class)){
|
for(Fi file : platform.getWorkshopContent(Map.class)){
|
||||||
try{
|
try{
|
||||||
Map map = loadMap(file, false);
|
Map map = loadMap(file, false);
|
||||||
map.workshop = true;
|
map.workshop = true;
|
||||||
@@ -183,7 +183,7 @@ public class Maps{
|
|||||||
StringMap tags = new StringMap(baseTags);
|
StringMap tags = new StringMap(baseTags);
|
||||||
String name = tags.get("name");
|
String name = tags.get("name");
|
||||||
if(name == null) throw new IllegalArgumentException("Can't save a map with no name. How did this happen?");
|
if(name == null) throw new IllegalArgumentException("Can't save a map with no name. How did this happen?");
|
||||||
FileHandle file;
|
Fi file;
|
||||||
|
|
||||||
//find map with the same exact display name
|
//find map with the same exact display name
|
||||||
Map other = maps.find(m -> m.name().equals(name));
|
Map other = maps.find(m -> m.name().equals(name));
|
||||||
@@ -244,8 +244,8 @@ public class Maps{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Import a map, then save it. This updates all values and stored data necessary. */
|
/** Import a map, then save it. This updates all values and stored data necessary. */
|
||||||
public void importMap(FileHandle file) throws IOException{
|
public void importMap(Fi file) throws IOException{
|
||||||
FileHandle dest = findFile();
|
Fi dest = findFile();
|
||||||
file.copyTo(dest);
|
file.copyTo(dest);
|
||||||
|
|
||||||
Map map = loadMap(dest, true);
|
Map map = loadMap(dest, true);
|
||||||
@@ -446,7 +446,7 @@ public class Maps{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Find a new filename to put a map to. */
|
/** Find a new filename to put a map to. */
|
||||||
private FileHandle findFile(){
|
private Fi findFile(){
|
||||||
//find a map name that isn't used.
|
//find a map name that isn't used.
|
||||||
int i = maps.size;
|
int i = maps.size;
|
||||||
while(customMapDirectory.child("map_" + i + "." + mapExtension).exists()){
|
while(customMapDirectory.child("map_" + i + "." + mapExtension).exists()){
|
||||||
@@ -455,7 +455,7 @@ public class Maps{
|
|||||||
return customMapDirectory.child("map_" + i + "." + mapExtension);
|
return customMapDirectory.child("map_" + i + "." + mapExtension);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map loadMap(FileHandle file, boolean custom) throws IOException{
|
private Map loadMap(Fi file, boolean custom) throws IOException{
|
||||||
Map map = MapIO.createMap(file, custom);
|
Map map = MapIO.createMap(file, custom);
|
||||||
|
|
||||||
if(map.name() == null){
|
if(map.name() == null){
|
||||||
|
|||||||
@@ -13,15 +13,15 @@ import io.anuke.mindustry.ui.dialogs.*;
|
|||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
import io.anuke.mindustry.world.blocks.*;
|
import io.anuke.mindustry.world.blocks.*;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.updateEditorOnChange;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public abstract class FilterOption{
|
public abstract class FilterOption{
|
||||||
public static final Boolf<Block> floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
public static final Boolf<Block> floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||||
public static final Boolf<Block> wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
public static final Boolf<Block> wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||||
public static final Boolf<Block> floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
public static final Boolf<Block> floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||||
public static final Boolf<Block> wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
public static final Boolf<Block> wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||||
public static final Boolf<Block> wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
public static final Boolf<Block> wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)));
|
||||||
public static final Boolf<Block> oresOnly = b -> b instanceof OverlayFloor && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
public static final Boolf<Block> oresOnly = b -> b instanceof OverlayFloor && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full));
|
||||||
public static final Boolf<Block> anyOptional = b -> floorsOnly.get(b) || wallsOnly.get(b) || oresOnly.get(b) || b == Blocks.air;
|
public static final Boolf<Block> anyOptional = b -> floorsOnly.get(b) || wallsOnly.get(b) || oresOnly.get(b) || b == Blocks.air;
|
||||||
|
|
||||||
public abstract void build(Table table);
|
public abstract void build(Table table);
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -138,26 +138,20 @@ public class ContentParser{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//try to parse "item/amount" syntax
|
//try to parse "item/amount" syntax
|
||||||
try{
|
if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){
|
||||||
if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){
|
String[] split = jsonData.asString().split("/");
|
||||||
String[] split = jsonData.asString().split("/");
|
|
||||||
|
|
||||||
return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}");
|
return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}");
|
||||||
}
|
|
||||||
}catch(Throwable ignored){
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//try to parse "liquid/amount" syntax
|
//try to parse "liquid/amount" syntax
|
||||||
try{
|
if(jsonData.isString() && jsonData.asString().contains("/")){
|
||||||
if(jsonData.isString() && jsonData.asString().contains("/")){
|
String[] split = jsonData.asString().split("/");
|
||||||
String[] split = jsonData.asString().split("/");
|
if(type == LiquidStack.class){
|
||||||
if(type == LiquidStack.class){
|
return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
||||||
return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
}else if(type == ConsumeLiquid.class){
|
||||||
}else if(type == ConsumeLiquid.class){
|
return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
||||||
return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}catch(Throwable ignored){
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(Content.class.isAssignableFrom(type)){
|
if(Content.class.isAssignableFrom(type)){
|
||||||
@@ -168,7 +162,7 @@ public class ContentParser{
|
|||||||
T two = (T)Vars.content.getByName(ctype, jsonData.asString());
|
T two = (T)Vars.content.getByName(ctype, jsonData.asString());
|
||||||
|
|
||||||
if(two != null) return two;
|
if(two != null) return two;
|
||||||
throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'.");
|
throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'.\nMake sure '" + jsonData.asString() + "' is spelled correctly, and that it really exists!\nThis may also occur because its file failed to parse.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,11 +252,15 @@ public class ContentParser{
|
|||||||
if(research[0] != null){
|
if(research[0] != null){
|
||||||
Block parent = find(ContentType.block, research[0]);
|
Block parent = find(ContentType.block, research[0]);
|
||||||
TechNode baseNode = TechTree.create(parent, block);
|
TechNode baseNode = TechTree.create(parent, block);
|
||||||
|
LoadedMod cur = currentMod;
|
||||||
|
|
||||||
postreads.add(() -> {
|
postreads.add(() -> {
|
||||||
|
currentContent = block;
|
||||||
|
currentMod = cur;
|
||||||
|
|
||||||
TechNode parnode = TechTree.all.find(t -> t.block == parent);
|
TechNode parnode = TechTree.all.find(t -> t.block == parent);
|
||||||
if(parnode == null){
|
if(parnode == null){
|
||||||
throw new ModLoadException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.", block);
|
throw new IllegalArgumentException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.");
|
||||||
}
|
}
|
||||||
if(!parnode.children.contains(baseNode)){
|
if(!parnode.children.contains(baseNode)){
|
||||||
parnode.children.add(baseNode);
|
parnode.children.add(baseNode);
|
||||||
@@ -304,7 +302,7 @@ public class ContentParser{
|
|||||||
if(value.has(key)){
|
if(value.has(key)){
|
||||||
return value.getString(key);
|
return value.getString(key);
|
||||||
}else{
|
}else{
|
||||||
throw new IllegalArgumentException((currentContent == null ? "" : currentContent.sourceFile + ": ") + "You are missing a \"" + key + "\". It must be added before the file can be parsed.");
|
throw new IllegalArgumentException("You are missing a \"" + key + "\". It must be added before the file can be parsed.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,13 +380,18 @@ public class ContentParser{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finishParsing(){
|
private void attempt(Runnable run){
|
||||||
try{
|
try{
|
||||||
reads.each(Runnable::run);
|
run.run();
|
||||||
postreads.each(Runnable::run);
|
}catch(Throwable t){
|
||||||
}catch(Exception e){
|
//don't overwrite double errors
|
||||||
Vars.mods.handleError(new ModLoadException("Error occurred parsing content: " + currentContent, currentContent, e), currentMod);
|
markError(currentContent, t);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finishParsing(){
|
||||||
|
reads.each(this::attempt);
|
||||||
|
postreads.each(this::attempt);
|
||||||
reads.clear();
|
reads.clear();
|
||||||
postreads.clear();
|
postreads.clear();
|
||||||
toBeParsed.clear();
|
toBeParsed.clear();
|
||||||
@@ -402,7 +405,7 @@ public class ContentParser{
|
|||||||
* @param file file that this content is being parsed from
|
* @param file file that this content is being parsed from
|
||||||
* @return the content that was parsed
|
* @return the content that was parsed
|
||||||
*/
|
*/
|
||||||
public Content parse(LoadedMod mod, String name, String json, FileHandle file, ContentType type) throws Exception{
|
public Content parse(LoadedMod mod, String name, String json, Fi file, ContentType type) throws Exception{
|
||||||
if(contentTypes.isEmpty()){
|
if(contentTypes.isEmpty()){
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
@@ -421,14 +424,49 @@ public class ContentParser{
|
|||||||
currentMod = mod;
|
currentMod = mod;
|
||||||
boolean located = locate(type, name) != null;
|
boolean located = locate(type, name) != null;
|
||||||
Content c = parsers.get(type).parse(mod.name, name, value);
|
Content c = parsers.get(type).parse(mod.name, name, value);
|
||||||
|
c.minfo.sourceFile = file;
|
||||||
toBeParsed.add(c);
|
toBeParsed.add(c);
|
||||||
|
|
||||||
if(!located){
|
if(!located){
|
||||||
c.sourceFile = file;
|
c.minfo.mod = mod;
|
||||||
c.mod = mod;
|
|
||||||
}
|
}
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void markError(Content content, LoadedMod mod, Fi file, Throwable error){
|
||||||
|
content.minfo.mod = mod;
|
||||||
|
content.minfo.sourceFile = file;
|
||||||
|
content.minfo.error = makeError(error, file);
|
||||||
|
content.minfo.baseError = error;
|
||||||
|
if(mod != null){
|
||||||
|
mod.erroredContent.add(content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void markError(Content content, Throwable error){
|
||||||
|
if(content.minfo != null && !content.hasErrored()){
|
||||||
|
markError(content, content.minfo.mod, content.minfo.sourceFile, error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeError(Throwable t, Fi file){
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("[lightgray]").append("File: ").append(file.name()).append("[]\n\n");
|
||||||
|
|
||||||
|
if(t.getMessage() != null && t instanceof JsonParseException){
|
||||||
|
builder.append("[accent][[JsonParse][] ").append(":\n").append(t.getMessage());
|
||||||
|
}else{
|
||||||
|
Array<Throwable> causes = Strings.getCauses(t);
|
||||||
|
for(Throwable e : causes){
|
||||||
|
builder.append("[accent][[").append(e.getClass().getSimpleName().replace("Exception", ""))
|
||||||
|
.append("][] ")
|
||||||
|
.append(e.getMessage() != null ?
|
||||||
|
e.getMessage().replace("io.anuke.mindustry.", "").replace("io.anuke.arc.", "") : "").append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
private <T extends MappableContent> T locate(ContentType type, String name){
|
private <T extends MappableContent> T locate(ContentType type, String name){
|
||||||
T first = Vars.content.getByName(type, name); //try vanilla replacement
|
T first = Vars.content.getByName(type, name); //try vanilla replacement
|
||||||
return first != null ? first : Vars.content.getByName(type, currentMod.name + "-" + name);
|
return first != null ? first : Vars.content.getByName(type, currentMod.name + "-" + name);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import io.anuke.mindustry.*;
|
|||||||
|
|
||||||
public class Mod{
|
public class Mod{
|
||||||
/** @return the config file for this plugin, as the file 'mods/[plugin-name]/config.json'.*/
|
/** @return the config file for this plugin, as the file 'mods/[plugin-name]/config.json'.*/
|
||||||
public FileHandle getConfig(){
|
public Fi getConfig(){
|
||||||
return Vars.mods.getConfig(this);
|
return Vars.mods.getConfig(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,67 +0,0 @@
|
|||||||
package io.anuke.mindustry.mod;
|
|
||||||
|
|
||||||
import io.anuke.arc.*;
|
|
||||||
import io.anuke.arc.collection.*;
|
|
||||||
import io.anuke.arc.graphics.*;
|
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
|
||||||
import io.anuke.arc.math.*;
|
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
|
||||||
import io.anuke.arc.util.*;
|
|
||||||
import io.anuke.mindustry.graphics.*;
|
|
||||||
import io.anuke.mindustry.mod.Mods.*;
|
|
||||||
import io.anuke.mindustry.ui.*;
|
|
||||||
|
|
||||||
public class ModCrashHandler{
|
|
||||||
|
|
||||||
public static void handle(Throwable t){
|
|
||||||
Array<Throwable> list = Strings.getCauses(t);
|
|
||||||
Throwable modCause = list.find(e -> e instanceof ModLoadException);
|
|
||||||
|
|
||||||
if(modCause != null && Fonts.outline != null){
|
|
||||||
String text = "[scarlet][[A fatal crash has occured while loading a mod!][]\n\nReason:[accent] " + modCause.getMessage();
|
|
||||||
String bottom = "[scarlet]The associated mod has been disabled. Swipe out of the app and launch it again.";
|
|
||||||
GlyphLayout layout = new GlyphLayout();
|
|
||||||
Core.atlas = TextureAtlas.blankAtlas();
|
|
||||||
Colors.put("accent", Pal.accent);
|
|
||||||
|
|
||||||
Core.app.addListener(new ApplicationListener(){
|
|
||||||
@Override
|
|
||||||
public void update(){
|
|
||||||
Core.graphics.clear(0.1f, 0.1f, 0.1f, 1f);
|
|
||||||
float rad = Math.min(Core.graphics.getWidth(), Core.graphics.getHeight()) / 2f / 1.3f;
|
|
||||||
Draw.color(Color.scarlet, Color.black, Mathf.absin(Core.graphics.getFrameId(), 15f, 0.6f));
|
|
||||||
Lines.stroke(Scl.scl(40f));
|
|
||||||
//Lines.poly2(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, 3, rad, 0f);
|
|
||||||
float cx = Core.graphics.getWidth()/2f, cy = Core.graphics.getHeight()/2f;
|
|
||||||
for(int i = 0; i < 3; i++){
|
|
||||||
float angle1 = i * 120f + 90f;
|
|
||||||
float angle2 = (i + 1) * 120f + 90f;
|
|
||||||
Tmp.v1.trnsExact(angle1, rad - Lines.getStroke()/2f).add(cx, cy);
|
|
||||||
Tmp.v2.trnsExact(angle2, rad - Lines.getStroke()/2f).add(cx, cy);
|
|
||||||
Tmp.v3.trnsExact(angle1, rad + Lines.getStroke()/2f).add(cx, cy);
|
|
||||||
Tmp.v4.trnsExact(angle2, rad + Lines.getStroke()/2f).add(cx, cy);
|
|
||||||
Fill.quad(Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y, Tmp.v4.x, Tmp.v4.y, Tmp.v3.x, Tmp.v3.y);
|
|
||||||
}
|
|
||||||
Lines.lineAngleCenter(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f - Scl.scl(5f), 90f, rad/3.1f);
|
|
||||||
Fill.square(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f + rad/2f - Scl.scl(15f), Lines.getStroke()/2f);
|
|
||||||
Draw.reset();
|
|
||||||
|
|
||||||
Fonts.outline.getData().markupEnabled = true;
|
|
||||||
layout.setText(Fonts.outline, text, Color.white, Core.graphics.getWidth(), Align.left, true);
|
|
||||||
Fonts.outline.draw(text, Core.graphics.getWidth()/2f - layout.width/2f, Core.graphics.getHeight() - Scl.scl(50f), Core.graphics.getWidth(), Align.left, true);
|
|
||||||
|
|
||||||
layout.setText(Fonts.outline, bottom, Color.white, Core.graphics.getWidth(), Align.left, true);
|
|
||||||
Fonts.outline.draw(bottom, Core.graphics.getWidth()/2f - layout.width/2f, layout.height + Scl.scl(10f), Core.graphics.getWidth(), Align.left, true);
|
|
||||||
Draw.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void resize(int width, int height){
|
|
||||||
Draw.proj().setOrtho(0, 0, width, height);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}else{
|
|
||||||
throw new RuntimeException(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -9,19 +9,22 @@ import io.anuke.arc.graphics.*;
|
|||||||
import io.anuke.arc.graphics.Texture.*;
|
import io.anuke.arc.graphics.Texture.*;
|
||||||
import io.anuke.arc.graphics.g2d.*;
|
import io.anuke.arc.graphics.g2d.*;
|
||||||
import io.anuke.arc.graphics.g2d.TextureAtlas.*;
|
import io.anuke.arc.graphics.g2d.TextureAtlas.*;
|
||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.scene.ui.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.arc.util.io.*;
|
import io.anuke.arc.util.io.*;
|
||||||
import io.anuke.arc.util.serialization.*;
|
import io.anuke.arc.util.serialization.*;
|
||||||
import io.anuke.arc.util.serialization.Jval.*;
|
import io.anuke.arc.util.serialization.Jval.*;
|
||||||
import io.anuke.mindustry.core.*;
|
import io.anuke.mindustry.core.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.graphics.MultiPacker.*;
|
import io.anuke.mindustry.graphics.MultiPacker.*;
|
||||||
import io.anuke.mindustry.plugin.*;
|
import io.anuke.mindustry.plugin.*;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.*;
|
||||||
|
import io.anuke.mindustry.ui.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.*;
|
import java.net.*;
|
||||||
@@ -32,52 +35,56 @@ public class Mods implements Loadable{
|
|||||||
private Json json = new Json();
|
private Json json = new Json();
|
||||||
private @Nullable Scripts scripts;
|
private @Nullable Scripts scripts;
|
||||||
private ContentParser parser = new ContentParser();
|
private ContentParser parser = new ContentParser();
|
||||||
private ObjectMap<String, Array<FileHandle>> bundles = new ObjectMap<>();
|
private ObjectMap<String, Array<Fi>> bundles = new ObjectMap<>();
|
||||||
private ObjectSet<String> specialFolders = ObjectSet.with("bundles", "sprites");
|
private ObjectSet<String> specialFolders = ObjectSet.with("bundles", "sprites", "sprites-override");
|
||||||
|
|
||||||
private int totalSprites;
|
private int totalSprites;
|
||||||
private MultiPacker packer;
|
private MultiPacker packer;
|
||||||
|
|
||||||
private Array<LoadedMod> loaded = new Array<>();
|
private Array<LoadedMod> mods = new Array<>();
|
||||||
private Array<LoadedMod> disabled = new Array<>();
|
|
||||||
private ObjectMap<Class<?>, ModMeta> metas = new ObjectMap<>();
|
private ObjectMap<Class<?>, ModMeta> metas = new ObjectMap<>();
|
||||||
private boolean requiresReload;
|
private boolean requiresReload;
|
||||||
|
|
||||||
|
public Mods(){
|
||||||
|
Events.on(ClientLoadEvent.class, e -> Core.app.post(this::checkWarnings));
|
||||||
|
Events.on(ContentReloadEvent.class, e -> Core.app.post(this::checkWarnings));
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns a file named 'config.json' in a special folder for the specified plugin.
|
/** Returns a file named 'config.json' in a special folder for the specified plugin.
|
||||||
* Call this in init(). */
|
* Call this in init(). */
|
||||||
public FileHandle getConfig(Mod mod){
|
public Fi getConfig(Mod mod){
|
||||||
ModMeta load = metas.get(mod.getClass());
|
ModMeta load = metas.get(mod.getClass());
|
||||||
if(load == null) throw new IllegalArgumentException("Mod is not loaded yet (or missing)!");
|
if(load == null) throw new IllegalArgumentException("Mod is not loaded yet (or missing)!");
|
||||||
return modDirectory.child(load.name).child("config.json");
|
return modDirectory.child(load.name).child("config.json");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns a list of files per mod subdirectory. */
|
/** Returns a list of files per mod subdirectory. */
|
||||||
public void listFiles(String directory, Cons2<LoadedMod, FileHandle> cons){
|
public void listFiles(String directory, Cons2<LoadedMod, Fi> cons){
|
||||||
for(LoadedMod mod : loaded){
|
eachEnabled(mod -> {
|
||||||
FileHandle file = mod.root.child(directory);
|
Fi file = mod.root.child(directory);
|
||||||
if(file.exists()){
|
if(file.exists()){
|
||||||
for(FileHandle child : file.list()){
|
for(Fi child : file.list()){
|
||||||
cons.get(mod, child);
|
cons.get(mod, child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return the loaded mod found by class, or null if not found. */
|
/** @return the loaded mod found by class, or null if not found. */
|
||||||
public @Nullable LoadedMod getMod(Class<? extends Mod> type){
|
public @Nullable LoadedMod getMod(Class<? extends Mod> type){
|
||||||
return loaded.find(l -> l.mod != null && l.mod.getClass() == type);
|
return mods.find(m -> m.enabled() && m.main != null && m.main.getClass() == type);//loaded.find(l -> l.mod != null && l.mod.getClass() == type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Imports an external mod file.*/
|
/** Imports an external mod file.*/
|
||||||
public void importMod(FileHandle file) throws IOException{
|
public void importMod(Fi file) throws IOException{
|
||||||
FileHandle dest = modDirectory.child(file.name());
|
Fi dest = modDirectory.child(file.name());
|
||||||
if(dest.exists()){
|
if(dest.exists()){
|
||||||
throw new IOException("A mod with the same filename already exists!");
|
throw new IOException("A mod with the same filename already exists!");
|
||||||
}
|
}
|
||||||
|
|
||||||
file.copyTo(dest);
|
file.copyTo(dest);
|
||||||
try{
|
try{
|
||||||
loaded.add(loadMod(dest));
|
mods.add(loadMod(dest));
|
||||||
requiresReload = true;
|
requiresReload = true;
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
dest.delete();
|
dest.delete();
|
||||||
@@ -91,19 +98,19 @@ public class Mods implements Loadable{
|
|||||||
/** Repacks all in-game sprites. */
|
/** Repacks all in-game sprites. */
|
||||||
@Override
|
@Override
|
||||||
public void loadAsync(){
|
public void loadAsync(){
|
||||||
if(loaded.isEmpty()) return;
|
if(!mods.contains(LoadedMod::enabled)) return;
|
||||||
Time.mark();
|
Time.mark();
|
||||||
|
|
||||||
packer = new MultiPacker();
|
packer = new MultiPacker();
|
||||||
|
|
||||||
for(LoadedMod mod : loaded){
|
eachEnabled(mod -> {
|
||||||
Array<FileHandle> sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png"));
|
Array<Fi> sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png"));
|
||||||
Array<FileHandle> overrides = mod.root.child("sprites-override").findAll(f -> f.extension().equals("png"));
|
Array<Fi> overrides = mod.root.child("sprites-override").findAll(f -> f.extension().equals("png"));
|
||||||
packSprites(sprites, mod, true);
|
packSprites(sprites, mod, true);
|
||||||
packSprites(overrides, mod, false);
|
packSprites(overrides, mod, false);
|
||||||
Log.debug("Packed {0} images for mod '{1}'.", sprites.size + overrides.size, mod.meta.name);
|
Log.debug("Packed {0} images for mod '{1}'.", sprites.size + overrides.size, mod.meta.name);
|
||||||
totalSprites += sprites.size + overrides.size;
|
totalSprites += sprites.size + overrides.size;
|
||||||
}
|
});
|
||||||
|
|
||||||
for(AtlasRegion region : Core.atlas.getRegions()){
|
for(AtlasRegion region : Core.atlas.getRegions()){
|
||||||
PageType type = getPage(region);
|
PageType type = getPage(region);
|
||||||
@@ -115,8 +122,8 @@ public class Mods implements Loadable{
|
|||||||
Log.debug("Time to pack textures: {0}", Time.elapsed());
|
Log.debug("Time to pack textures: {0}", Time.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void packSprites(Array<FileHandle> sprites, LoadedMod mod, boolean prefix){
|
private void packSprites(Array<Fi> sprites, LoadedMod mod, boolean prefix){
|
||||||
for(FileHandle file : sprites){
|
for(Fi file : sprites){
|
||||||
try(InputStream stream = file.read()){
|
try(InputStream stream = file.read()){
|
||||||
byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512));
|
byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512));
|
||||||
Pixmap pixmap = new Pixmap(bytes, 0, bytes.length);
|
Pixmap pixmap = new Pixmap(bytes, 0, bytes.length);
|
||||||
@@ -149,7 +156,7 @@ public class Mods implements Loadable{
|
|||||||
//generate new icons
|
//generate new icons
|
||||||
for(Array<Content> arr : content.getContentMap()){
|
for(Array<Content> arr : content.getContentMap()){
|
||||||
arr.each(c -> {
|
arr.each(c -> {
|
||||||
if(c instanceof UnlockableContent && c.mod != null){
|
if(c instanceof UnlockableContent && c.minfo.mod != null){
|
||||||
UnlockableContent u = (UnlockableContent)c;
|
UnlockableContent u = (UnlockableContent)c;
|
||||||
u.createIcons(packer);
|
u.createIcons(packer);
|
||||||
}
|
}
|
||||||
@@ -176,7 +183,7 @@ public class Mods implements Loadable{
|
|||||||
PageType.main;
|
PageType.main;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PageType getPage(FileHandle file){
|
private PageType getPage(Fi file){
|
||||||
String parent = file.parent().name();
|
String parent = file.parent().name();
|
||||||
return
|
return
|
||||||
parent.equals("environment") ? PageType.environment :
|
parent.equals("environment") ? PageType.environment :
|
||||||
@@ -188,7 +195,7 @@ public class Mods implements Loadable{
|
|||||||
|
|
||||||
/** Removes a mod file and marks it for requiring a restart. */
|
/** Removes a mod file and marks it for requiring a restart. */
|
||||||
public void removeMod(LoadedMod mod){
|
public void removeMod(LoadedMod mod){
|
||||||
if(mod.root instanceof ZipFileHandle){
|
if(mod.root instanceof ZipFi){
|
||||||
mod.root.delete();
|
mod.root.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,8 +205,7 @@ public class Mods implements Loadable{
|
|||||||
ui.showErrorMessage("$mod.delete.error");
|
ui.showErrorMessage("$mod.delete.error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
loaded.remove(mod);
|
mods.remove(mod);
|
||||||
disabled.remove(mod);
|
|
||||||
requiresReload = true;
|
requiresReload = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -219,17 +225,13 @@ public class Mods implements Loadable{
|
|||||||
|
|
||||||
/** Loads all mods from the folder, but does not call any methods on them.*/
|
/** Loads all mods from the folder, but does not call any methods on them.*/
|
||||||
public void load(){
|
public void load(){
|
||||||
for(FileHandle file : modDirectory.list()){
|
for(Fi file : modDirectory.list()){
|
||||||
if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && (file.child("mod.json").exists() || file.child("mod.hjson").exists()))) continue;
|
if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && (file.child("mod.json").exists() || file.child("mod.hjson").exists()))) continue;
|
||||||
|
|
||||||
Log.debug("[Mods] Loading mod {0}", file);
|
Log.debug("[Mods] Loading mod {0}", file);
|
||||||
try{
|
try{
|
||||||
LoadedMod mod = loadMod(file);
|
LoadedMod mod = loadMod(file);
|
||||||
if(mod.enabled() || headless){
|
mods.add(mod);
|
||||||
loaded.add(mod);
|
|
||||||
}else{
|
|
||||||
disabled.add(mod);
|
|
||||||
}
|
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Log.err("Failed to load mod file {0}. Skipping.", file);
|
Log.err("Failed to load mod file {0}. Skipping.", file);
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
@@ -237,14 +239,10 @@ public class Mods implements Loadable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//load workshop mods now
|
//load workshop mods now
|
||||||
for(FileHandle file : platform.getWorkshopContent(LoadedMod.class)){
|
for(Fi file : platform.getWorkshopContent(LoadedMod.class)){
|
||||||
try{
|
try{
|
||||||
LoadedMod mod = loadMod(file);
|
LoadedMod mod = loadMod(file);
|
||||||
if(mod.enabled()){
|
mods.add(mod);
|
||||||
loaded.add(mod);
|
|
||||||
}else{
|
|
||||||
disabled.add(mod);
|
|
||||||
}
|
|
||||||
mod.addSteamID(file.name());
|
mod.addSteamID(file.name());
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Log.err("Failed to load mod workshop file {0}. Skipping.", file);
|
Log.err("Failed to load mod workshop file {0}. Skipping.", file);
|
||||||
@@ -252,28 +250,27 @@ public class Mods implements Loadable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveDependencies();
|
resolveModState();
|
||||||
|
sortMods();
|
||||||
//sort mods to make sure servers handle them properly.
|
|
||||||
loaded.sort(Structs.comparing(m -> m.name));
|
|
||||||
|
|
||||||
buildFiles();
|
buildFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resolveDependencies(){
|
private void sortMods(){
|
||||||
Array<LoadedMod> incompatible = loaded.select(m -> !m.isSupported());
|
//sort mods to make sure servers handle them properly and they appear correctly in the dialog
|
||||||
loaded.removeAll(incompatible);
|
mods.sort(Structs.comps(Structs.comparingInt(m -> m.state.ordinal()), Structs.comparing(m -> m.name)));
|
||||||
disabled.addAll(incompatible);
|
}
|
||||||
|
|
||||||
for(LoadedMod mod : Array.<LoadedMod>withArrays(loaded, disabled)){
|
private void resolveModState(){
|
||||||
updateDependencies(mod);
|
mods.each(this::updateDependencies);
|
||||||
|
|
||||||
|
for(LoadedMod mod : mods){
|
||||||
|
mod.state =
|
||||||
|
!mod.isSupported() ? ModState.unsupported :
|
||||||
|
mod.hasUnmetDependencies() ? ModState.missingDependencies :
|
||||||
|
!mod.shouldBeEnabled() ? ModState.disabled :
|
||||||
|
ModState.enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
disabled.addAll(loaded.select(LoadedMod::hasUnmetDependencies));
|
|
||||||
loaded.removeAll(LoadedMod::hasUnmetDependencies);
|
|
||||||
disabled.each(mod -> setEnabled(mod, false));
|
|
||||||
disabled.distinct();
|
|
||||||
loaded.distinct();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateDependencies(LoadedMod mod){
|
private void updateDependencies(LoadedMod mod){
|
||||||
@@ -298,23 +295,23 @@ public class Mods implements Loadable{
|
|||||||
private Array<LoadedMod> orderedMods(){
|
private Array<LoadedMod> orderedMods(){
|
||||||
ObjectSet<LoadedMod> visited = new ObjectSet<>();
|
ObjectSet<LoadedMod> visited = new ObjectSet<>();
|
||||||
Array<LoadedMod> result = new Array<>();
|
Array<LoadedMod> result = new Array<>();
|
||||||
for(LoadedMod mod : loaded){
|
eachEnabled(mod -> {
|
||||||
if(!visited.contains(mod)){
|
if(!visited.contains(mod)){
|
||||||
topoSort(mod, result, visited);
|
topoSort(mod, result, visited);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoadedMod locateMod(String name){
|
private LoadedMod locateMod(String name){
|
||||||
return loaded.find(mod -> mod.name.equals(name));
|
return mods.find(mod -> mod.enabled() && mod.name.equals(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildFiles(){
|
private void buildFiles(){
|
||||||
for(LoadedMod mod : orderedMods()){
|
for(LoadedMod mod : orderedMods()){
|
||||||
boolean zipFolder = !mod.file.isDirectory() && mod.root.parent() != null;
|
boolean zipFolder = !mod.file.isDirectory() && mod.root.parent() != null;
|
||||||
String parentName = zipFolder ? mod.root.name() : null;
|
String parentName = zipFolder ? mod.root.name() : null;
|
||||||
for(FileHandle file : mod.root.list()){
|
for(Fi file : mod.root.list()){
|
||||||
//ignore special folders like bundles or sprites
|
//ignore special folders like bundles or sprites
|
||||||
if(file.isDirectory() && !specialFolders.contains(file.name())){
|
if(file.isDirectory() && !specialFolders.contains(file.name())){
|
||||||
//TODO calling child/parent on these files will give you gibberish; create wrapper class.
|
//TODO calling child/parent on these files will give you gibberish; create wrapper class.
|
||||||
@@ -324,9 +321,9 @@ public class Mods implements Loadable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//load up bundles.
|
//load up bundles.
|
||||||
FileHandle folder = mod.root.child("bundles");
|
Fi folder = mod.root.child("bundles");
|
||||||
if(folder.exists()){
|
if(folder.exists()){
|
||||||
for(FileHandle file : folder.list()){
|
for(Fi file : folder.list()){
|
||||||
if(file.name().startsWith("bundle") && file.extension().equals("properties")){
|
if(file.name().startsWith("bundle") && file.extension().equals("properties")){
|
||||||
String name = file.nameWithoutExtension();
|
String name = file.nameWithoutExtension();
|
||||||
bundles.getOr(name, Array::new).add(file);
|
bundles.getOr(name, Array::new).add(file);
|
||||||
@@ -340,25 +337,79 @@ public class Mods implements Loadable{
|
|||||||
while(bundle != null){
|
while(bundle != null){
|
||||||
String str = bundle.getLocale().toString();
|
String str = bundle.getLocale().toString();
|
||||||
String locale = "bundle" + (str.isEmpty() ? "" : "_" + str);
|
String locale = "bundle" + (str.isEmpty() ? "" : "_" + str);
|
||||||
for(FileHandle file : bundles.getOr(locale, Array::new)){
|
for(Fi file : bundles.getOr(locale, Array::new)){
|
||||||
try{
|
try{
|
||||||
PropertiesUtils.load(bundle.getProperties(), file.reader());
|
PropertiesUtils.load(bundle.getProperties(), file.reader());
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
throw new RuntimeException("Error loading bundle: " + file + "/" + locale, e);
|
Log.err("Error loading bundle: " + file + "/" + locale, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bundle = bundle.getParent();
|
bundle = bundle.getParent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Check all warnings related to content and show relevant dialogs. Client only. */
|
||||||
|
private void checkWarnings(){
|
||||||
|
//show 'scripts have errored' info
|
||||||
|
if(scripts != null && scripts.hasErrored()){
|
||||||
|
Core.settings.getBoolOnce("scripts-errored2", () -> ui.showErrorMessage("$mod.scripts.unsupported"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//show list of errored content
|
||||||
|
if(mods.contains(LoadedMod::hasContentErrors)){
|
||||||
|
ui.loadfrag.hide();
|
||||||
|
new Dialog(""){{
|
||||||
|
|
||||||
|
setFillParent(true);
|
||||||
|
cont.margin(15);
|
||||||
|
cont.add("$error.title");
|
||||||
|
cont.row();
|
||||||
|
cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet);
|
||||||
|
cont.row();
|
||||||
|
cont.add("$mod.errors").wrap().growX().center().get().setAlignment(Align.center);
|
||||||
|
cont.row();
|
||||||
|
cont.pane(p -> {
|
||||||
|
mods.each(m -> m.enabled() && m.hasContentErrors(), m -> {
|
||||||
|
p.add(m.name).color(Pal.accent).left();
|
||||||
|
p.row();
|
||||||
|
p.addImage().fillX().pad(4).color(Pal.accent);
|
||||||
|
p.row();
|
||||||
|
p.table(d -> {
|
||||||
|
d.left().marginLeft(15f);
|
||||||
|
for(Content c : m.erroredContent){
|
||||||
|
d.add(c.minfo.sourceFile.nameWithoutExtension()).left().padRight(10);
|
||||||
|
d.addImageTextButton("$details", Icon.arrowDownSmall, Styles.transt, () -> {
|
||||||
|
new Dialog(""){{
|
||||||
|
setFillParent(true);
|
||||||
|
cont.pane(e -> e.add(c.minfo.error)).grow();
|
||||||
|
cont.row();
|
||||||
|
cont.addImageTextButton("$ok", Icon.backSmall, this::hide).size(240f, 60f);
|
||||||
|
}}.show();
|
||||||
|
}).size(190f, 50f).left().marginLeft(6);
|
||||||
|
d.row();
|
||||||
|
}
|
||||||
|
}).left();
|
||||||
|
p.row();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cont.row();
|
||||||
|
cont.addButton("$ok", this::hide).size(300, 50);
|
||||||
|
}}.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasContentErrors(){
|
||||||
|
return mods.contains(LoadedMod::hasContentErrors);
|
||||||
|
}
|
||||||
|
|
||||||
/** Reloads all mod content. How does this even work? I refuse to believe that it functions correctly.*/
|
/** Reloads all mod content. How does this even work? I refuse to believe that it functions correctly.*/
|
||||||
public void reloadContent(){
|
public void reloadContent(){
|
||||||
//epic memory leak
|
//epic memory leak
|
||||||
//TODO make it less epic
|
//TODO make it less epic
|
||||||
Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas"));
|
Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas"));
|
||||||
|
|
||||||
loaded.clear();
|
mods.clear();
|
||||||
disabled.clear();
|
|
||||||
load();
|
load();
|
||||||
Sounds.dispose();
|
Sounds.dispose();
|
||||||
Sounds.load();
|
Sounds.load();
|
||||||
@@ -378,13 +429,10 @@ public class Mods implements Loadable{
|
|||||||
content.load();
|
content.load();
|
||||||
content.loadColors();
|
content.loadColors();
|
||||||
data.load();
|
data.load();
|
||||||
|
Core.atlas.getTextures().each(t -> t.setFilter(Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest));
|
||||||
requiresReload = false;
|
requiresReload = false;
|
||||||
|
|
||||||
Events.fire(new ContentReloadEvent());
|
Events.fire(new ContentReloadEvent());
|
||||||
|
|
||||||
if(scripts != null && scripts.hasErrored()){
|
|
||||||
Core.app.post(() -> Core.settings.getBoolOnce("scripts-errored", () -> ui.showErrorMessage("$mod.scripts.unsupported")));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** This must be run on the main thread! */
|
/** This must be run on the main thread! */
|
||||||
@@ -392,13 +440,13 @@ public class Mods implements Loadable{
|
|||||||
Time.mark();
|
Time.mark();
|
||||||
|
|
||||||
try{
|
try{
|
||||||
for(LoadedMod mod : loaded){
|
eachEnabled(mod -> {
|
||||||
if(mod.root.child("scripts").exists()){
|
if(mod.root.child("scripts").exists()){
|
||||||
content.setCurrentMod(mod);
|
content.setCurrentMod(mod);
|
||||||
mod.scripts = mod.root.child("scripts").findAll(f -> f.extension().equals("js"));
|
mod.scripts = mod.root.child("scripts").findAll(f -> f.extension().equals("js"));
|
||||||
Log.debug("[{0}] Found {1} scripts.", mod.meta.name, mod.scripts.size);
|
Log.debug("[{0}] Found {1} scripts.", mod.meta.name, mod.scripts.size);
|
||||||
|
|
||||||
for(FileHandle file : mod.scripts){
|
for(Fi file : mod.scripts){
|
||||||
try{
|
try{
|
||||||
if(scripts == null){
|
if(scripts == null){
|
||||||
scripts = platform.createScripts();
|
scripts = platform.createScripts();
|
||||||
@@ -408,13 +456,12 @@ public class Mods implements Loadable{
|
|||||||
Core.app.post(() -> {
|
Core.app.post(() -> {
|
||||||
Log.err("Error loading script {0} for mod {1}.", file.name(), mod.meta.name);
|
Log.err("Error loading script {0} for mod {1}.", file.name(), mod.meta.name);
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
//if(!headless) ui.showException(e);
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}finally{
|
}finally{
|
||||||
content.setCurrentMod(null);
|
content.setCurrentMod(null);
|
||||||
}
|
}
|
||||||
@@ -427,10 +474,10 @@ public class Mods implements Loadable{
|
|||||||
|
|
||||||
class LoadRun implements Comparable<LoadRun>{
|
class LoadRun implements Comparable<LoadRun>{
|
||||||
final ContentType type;
|
final ContentType type;
|
||||||
final FileHandle file;
|
final Fi file;
|
||||||
final LoadedMod mod;
|
final LoadedMod mod;
|
||||||
|
|
||||||
public LoadRun(ContentType type, FileHandle file, LoadedMod mod){
|
public LoadRun(ContentType type, Fi file, LoadedMod mod){
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.mod = mod;
|
this.mod = mod;
|
||||||
@@ -448,11 +495,11 @@ public class Mods implements Loadable{
|
|||||||
|
|
||||||
for(LoadedMod mod : orderedMods()){
|
for(LoadedMod mod : orderedMods()){
|
||||||
if(mod.root.child("content").exists()){
|
if(mod.root.child("content").exists()){
|
||||||
FileHandle contentRoot = mod.root.child("content");
|
Fi contentRoot = mod.root.child("content");
|
||||||
for(ContentType type : ContentType.all){
|
for(ContentType type : ContentType.all){
|
||||||
FileHandle folder = contentRoot.child(type.name().toLowerCase() + "s");
|
Fi folder = contentRoot.child(type.name().toLowerCase() + "s");
|
||||||
if(folder.exists()){
|
if(folder.exists()){
|
||||||
for(FileHandle file : folder.list()){
|
for(Fi file : folder.list()){
|
||||||
if(file.extension().equals("json") || file.extension().equals("hjson")){
|
if(file.extension().equals("json") || file.extension().equals("hjson")){
|
||||||
runs.add(new LoadRun(type, file, mod));
|
runs.add(new LoadRun(type, file, mod));
|
||||||
}
|
}
|
||||||
@@ -464,56 +511,43 @@ public class Mods implements Loadable{
|
|||||||
|
|
||||||
//make sure mod content is in proper order
|
//make sure mod content is in proper order
|
||||||
runs.sort();
|
runs.sort();
|
||||||
runs.each(l -> safeRun(l.mod, () -> {
|
for(LoadRun l : runs){
|
||||||
|
Content current = content.getLastAdded();
|
||||||
try{
|
try{
|
||||||
//this binds the content but does not load it entirely
|
//this binds the content but does not load it entirely
|
||||||
Content loaded = parser.parse(l.mod, l.file.nameWithoutExtension(), l.file.readString("UTF-8"), l.file, l.type);
|
Content loaded = parser.parse(l.mod, l.file.nameWithoutExtension(), l.file.readString("UTF-8"), l.file, l.type);
|
||||||
Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name,
|
Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name, (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded));
|
||||||
(loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded));
|
}catch(Throwable e){
|
||||||
}catch(Exception e){
|
if(current != content.getLastAdded() && content.getLastAdded() != null){
|
||||||
throw new RuntimeException("Failed to parse content file '" + l.file + "' for mod '" + l.mod.meta.name + "'.", e);
|
parser.markError(content.getLastAdded(), l.mod, l.file, e);
|
||||||
|
}else{
|
||||||
|
ErrorContent error = new ErrorContent();
|
||||||
|
parser.markError(error, l.mod, l.file, e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}));
|
}
|
||||||
|
|
||||||
//this finishes parsing content fields
|
//this finishes parsing content fields
|
||||||
parser.finishParsing();
|
parser.finishParsing();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return all loaded mods. */
|
public void handleContentError(Content content, Throwable error){
|
||||||
public Array<LoadedMod> all(){
|
parser.markError(content, error);
|
||||||
return loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return all disabled mods. */
|
|
||||||
public Array<LoadedMod> disabled(){
|
|
||||||
return disabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @return a list of mod names only, without versions. */
|
|
||||||
public Array<String> getModNames(){
|
|
||||||
return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return a list of mods and versions, in the format name:version. */
|
/** @return a list of mods and versions, in the format name:version. */
|
||||||
public Array<String> getModStrings(){
|
public Array<String> getModStrings(){
|
||||||
return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version);
|
return mods.select(l -> !l.meta.hidden && l.enabled()).map(l -> l.name + ":" + l.meta.version);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Makes a mod enabled or disabled. shifts it.*/
|
/** Makes a mod enabled or disabled. shifts it.*/
|
||||||
public void setEnabled(LoadedMod mod, boolean enabled){
|
public void setEnabled(LoadedMod mod, boolean enabled){
|
||||||
if(mod.enabled() != enabled){
|
if(mod.enabled() != enabled){
|
||||||
Core.settings.putSave("mod-" + mod.name + "-enabled", enabled);
|
Core.settings.putSave("mod-" + mod.name + "-enabled", enabled);
|
||||||
Core.settings.save();
|
|
||||||
requiresReload = true;
|
requiresReload = true;
|
||||||
if(!enabled){
|
mod.state = enabled ? ModState.enabled : ModState.disabled;
|
||||||
loaded.remove(mod);
|
mods.each(this::updateDependencies);
|
||||||
if(!disabled.contains(mod)) disabled.add(mod);
|
sortMods();
|
||||||
}else{
|
|
||||||
if(!loaded.contains(mod)) loaded.add(mod);
|
|
||||||
disabled.remove(mod);
|
|
||||||
}
|
|
||||||
loaded.each(this::updateDependencies);
|
|
||||||
disabled.each(this::updateDependencies);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,55 +564,37 @@ public class Mods implements Loadable{
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Iterates through each mod with a main class.*/
|
public Array<LoadedMod> list(){
|
||||||
public void each(Cons<Mod> cons){
|
return mods;
|
||||||
loaded.each(p -> p.mod != null, p -> safeRun(p, () -> cons.get(p.mod)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleError(Throwable t, LoadedMod mod){
|
/** Iterates through each mod with a main class. */
|
||||||
Array<Throwable> causes = Strings.getCauses(t);
|
public void eachClass(Cons<Mod> cons){
|
||||||
Content content = null;
|
mods.each(p -> p.main != null, p -> contextRun(p, () -> cons.get(p.main)));
|
||||||
for(Throwable e : causes){
|
|
||||||
if(e instanceof ModLoadException && ((ModLoadException) e).content != null){
|
|
||||||
content = ((ModLoadException) e).content;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
String realCause = "<???>";
|
|
||||||
for(int i = causes.size -1 ; i >= 0; i--){
|
|
||||||
if(causes.get(i).getMessage() != null){
|
|
||||||
realCause = causes.get(i).getMessage();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setEnabled(mod, false);
|
|
||||||
|
|
||||||
if(content != null){
|
|
||||||
throw new ModLoadException(Strings.format("Error loading '{0}' from mod '{1}' ({2}):\n{3}",
|
|
||||||
content, mod.meta.name, content.sourceFile == null ? "<unknown file>" : content.sourceFile.name(), realCause), content, t);
|
|
||||||
}else{
|
|
||||||
throw new ModLoadException("Error loading mod " + mod.meta.name, t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void safeRun(LoadedMod mod, Runnable run){
|
/** Iterates through each enabled mod. */
|
||||||
|
public void eachEnabled(Cons<LoadedMod> cons){
|
||||||
|
mods.each(LoadedMod::enabled, cons);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void contextRun(LoadedMod mod, Runnable run){
|
||||||
try{
|
try{
|
||||||
run.run();
|
run.run();
|
||||||
}catch(Throwable t){
|
}catch(Throwable t){
|
||||||
handleError(t, mod);
|
throw new RuntimeException("Error loading mod " + mod.meta.name, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Loads a mod file+meta, but does not add it to the list.
|
/** Loads a mod file+meta, but does not add it to the list.
|
||||||
* Note that directories can be loaded as mods.*/
|
* Note that directories can be loaded as mods.*/
|
||||||
private LoadedMod loadMod(FileHandle sourceFile) throws Exception{
|
private LoadedMod loadMod(Fi sourceFile) throws Exception{
|
||||||
FileHandle zip = sourceFile.isDirectory() ? sourceFile : new ZipFileHandle(sourceFile);
|
Fi zip = sourceFile.isDirectory() ? sourceFile : new ZipFi(sourceFile);
|
||||||
if(zip.list().length == 1 && zip.list()[0].isDirectory()){
|
if(zip.list().length == 1 && zip.list()[0].isDirectory()){
|
||||||
zip = zip.list()[0];
|
zip = zip.list()[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
FileHandle metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("mod.hjson").exists() ? zip.child("mod.hjson") : zip.child("plugin.json");
|
Fi metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("mod.hjson").exists() ? zip.child("mod.hjson") : zip.child("plugin.json");
|
||||||
if(!metaf.exists()){
|
if(!metaf.exists()){
|
||||||
Log.warn("Mod {0} doesn't have a 'mod.json'/'plugin.json'/'mod.js' file, skipping.", sourceFile);
|
Log.warn("Mod {0} doesn't have a 'mod.json'/'plugin.json'/'mod.js' file, skipping.", sourceFile);
|
||||||
throw new IllegalArgumentException("No mod.json found.");
|
throw new IllegalArgumentException("No mod.json found.");
|
||||||
@@ -589,13 +605,13 @@ public class Mods implements Loadable{
|
|||||||
String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main;
|
String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main;
|
||||||
String baseName = meta.name.toLowerCase().replace(" ", "-");
|
String baseName = meta.name.toLowerCase().replace(" ", "-");
|
||||||
|
|
||||||
if(loaded.contains(m -> m.name.equals(baseName)) || disabled.contains(m -> m.name.equals(baseName))){
|
if(mods.contains(m -> m.name.equals(baseName))){
|
||||||
throw new IllegalArgumentException("A mod with the name '" + baseName + "' is already imported.");
|
throw new IllegalArgumentException("A mod with the name '" + baseName + "' is already imported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
Mod mainMod;
|
Mod mainMod;
|
||||||
|
|
||||||
FileHandle mainFile = zip;
|
Fi mainFile = zip;
|
||||||
String[] path = (mainClass.replace('.', '/') + ".class").split("/");
|
String[] path = (mainClass.replace('.', '/') + ".class").split("/");
|
||||||
for(String str : path){
|
for(String str : path){
|
||||||
if(!str.isEmpty()){
|
if(!str.isEmpty()){
|
||||||
@@ -629,11 +645,11 @@ public class Mods implements Loadable{
|
|||||||
/** Represents a plugin that has been loaded from a jar file.*/
|
/** Represents a plugin that has been loaded from a jar file.*/
|
||||||
public static class LoadedMod implements Publishable{
|
public static class LoadedMod implements Publishable{
|
||||||
/** The location of this mod's zip file/folder on the disk. */
|
/** The location of this mod's zip file/folder on the disk. */
|
||||||
public final FileHandle file;
|
public final Fi file;
|
||||||
/** The root zip file; points to the contents of this mod. In the case of folders, this is the same as the mod's file. */
|
/** The root zip file; points to the contents of this mod. In the case of folders, this is the same as the mod's file. */
|
||||||
public final FileHandle root;
|
public final Fi root;
|
||||||
/** The mod's main class; may be null. */
|
/** The mod's main class; may be null. */
|
||||||
public final @Nullable Mod mod;
|
public final @Nullable Mod main;
|
||||||
/** Internal mod name. Used for textures. */
|
/** Internal mod name. Used for textures. */
|
||||||
public final String name;
|
public final String name;
|
||||||
/** This mod's metadata. */
|
/** This mod's metadata. */
|
||||||
@@ -643,17 +659,25 @@ public class Mods implements Loadable{
|
|||||||
/** All missing dependencies of this mod as strings. */
|
/** All missing dependencies of this mod as strings. */
|
||||||
public Array<String> missingDependencies = new Array<>();
|
public Array<String> missingDependencies = new Array<>();
|
||||||
/** Script files to run. */
|
/** Script files to run. */
|
||||||
public Array<FileHandle> scripts = new Array<>();
|
public Array<Fi> scripts = new Array<>();
|
||||||
|
/** Content with intialization code. */
|
||||||
|
public ObjectSet<Content> erroredContent = new ObjectSet<>();
|
||||||
|
/** Current state of this mod. */
|
||||||
|
public ModState state = ModState.enabled;
|
||||||
|
|
||||||
public LoadedMod(FileHandle file, FileHandle root, Mod mod, ModMeta meta){
|
public LoadedMod(Fi file, Fi root, Mod main, ModMeta meta){
|
||||||
this.root = root;
|
this.root = root;
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.mod = mod;
|
this.main = main;
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
this.name = meta.name.toLowerCase().replace(" ", "-");
|
this.name = meta.name.toLowerCase().replace(" ", "-");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean enabled(){
|
public boolean enabled(){
|
||||||
|
return state == ModState.enabled || state == ModState.contentErrors;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean shouldBeEnabled(){
|
||||||
return Core.settings.getBool("mod-" + name + "-enabled", true);
|
return Core.settings.getBool("mod-" + name + "-enabled", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,6 +685,10 @@ public class Mods implements Loadable{
|
|||||||
return !missingDependencies.isEmpty();
|
return !missingDependencies.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasContentErrors(){
|
||||||
|
return !erroredContent.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
/** @return whether this mod is supported by the game verison */
|
/** @return whether this mod is supported by the game verison */
|
||||||
public boolean isSupported(){
|
public boolean isSupported(){
|
||||||
if(Version.build <= 0 || meta.minGameVersion == null) return true;
|
if(Version.build <= 0 || meta.minGameVersion == null) return true;
|
||||||
@@ -706,12 +734,12 @@ public class Mods implements Loadable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle createSteamFolder(String id){
|
public Fi createSteamFolder(String id){
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FileHandle createSteamPreview(String id){
|
public Fi createSteamPreview(String id){
|
||||||
return file.child("preview.png");
|
return file.child("preview.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -752,37 +780,11 @@ public class Mods implements Loadable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Thrown when an error occurs while loading a mod.*/
|
public enum ModState{
|
||||||
public static class ModLoadException extends RuntimeException{
|
enabled,
|
||||||
public Content content;
|
contentErrors,
|
||||||
public LoadedMod mod;
|
missingDependencies,
|
||||||
|
unsupported,
|
||||||
public ModLoadException(String message, Throwable cause){
|
disabled,
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModLoadException(String message, @Nullable Content content, Throwable cause){
|
|
||||||
super(message, cause);
|
|
||||||
this.content = content;
|
|
||||||
if(content != null){
|
|
||||||
this.mod = content.mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModLoadException(@Nullable Content content, Throwable cause){
|
|
||||||
super(cause);
|
|
||||||
this.content = content;
|
|
||||||
if(content != null){
|
|
||||||
this.mod = content.mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModLoadException(String message, @Nullable Content content){
|
|
||||||
super(message);
|
|
||||||
this.content = content;
|
|
||||||
if(content != null){
|
|
||||||
this.mod = content.mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class Scripts implements Disposable{
|
|||||||
Log.log(level, "[{0}]: {1}", source, message);
|
Log.log(level, "[{0}]: {1}", source, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(LoadedMod mod, FileHandle file){
|
public void run(LoadedMod mod, Fi file){
|
||||||
run(wrapper.replace("$SCRIPT_NAME$", mod.name + "/" + file.nameWithoutExtension()).replace("$CODE$", file.readString()).replace("$MOD_NAME$", mod.name), file.name());
|
run(wrapper.replace("$SCRIPT_NAME$", mod.name + "/" + file.nameWithoutExtension()).replace("$CODE$", file.readString()).replace("$MOD_NAME$", mod.name), file.name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import static io.anuke.mindustry.Vars.net;
|
|||||||
public class CrashSender{
|
public class CrashSender{
|
||||||
|
|
||||||
public static void send(Throwable exception, Cons<File> writeListener){
|
public static void send(Throwable exception, Cons<File> writeListener){
|
||||||
|
|
||||||
try{
|
try{
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
|
|
||||||
@@ -44,20 +45,19 @@ public class CrashSender{
|
|||||||
}else{
|
}else{
|
||||||
Version.build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
|
Version.build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
|
||||||
}
|
}
|
||||||
}catch(Throwable ignored){
|
}catch(Throwable e){
|
||||||
ignored.printStackTrace();
|
e.printStackTrace();
|
||||||
Log.err("Failed to parse version.");
|
Log.err("Failed to parse version.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
File file = new File(OS.getAppDataDirectoryString(Vars.appName), "crashes/crash-report-" + new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss").format(new Date()) + ".txt");
|
File file = new File(OS.getAppDataDirectoryString(Vars.appName), "crashes/crash-report-" + new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss").format(new Date()) + ".txt");
|
||||||
new FileHandle(OS.getAppDataDirectoryString(Vars.appName)).child("crashes").mkdirs();
|
new Fi(OS.getAppDataDirectoryString(Vars.appName)).child("crashes").mkdirs();
|
||||||
new FileHandle(file).writeString(parseException(exception));
|
new Fi(file).writeString(parseException(exception));
|
||||||
writeListener.get(file);
|
writeListener.get(file);
|
||||||
}catch(Throwable e){
|
}catch(Throwable e){
|
||||||
e.printStackTrace();
|
Log.err("Failed to save local crash report.", e);
|
||||||
Log.err("Failed to save local crash report.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
@@ -69,6 +69,14 @@ public class CrashSender{
|
|||||||
//if there's no settings init we don't know what the user wants but chances are it's an important crash, so send it anyway
|
//if there's no settings init we don't know what the user wants but chances are it's an important crash, so send it anyway
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
//check any mods - if there are any, don't send reports
|
||||||
|
if(Vars.mods != null && !Vars.mods.list().isEmpty()){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}catch(Throwable ignored){
|
||||||
|
}
|
||||||
|
|
||||||
//do not send exceptions that occur for versions that can't be parsed
|
//do not send exceptions that occur for versions that can't be parsed
|
||||||
if(Version.number == 0){
|
if(Version.number == 0){
|
||||||
return;
|
return;
|
||||||
|
|||||||
12
core/src/io/anuke/mindustry/type/ErrorContent.java
Normal file
12
core/src/io/anuke/mindustry/type/ErrorContent.java
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package io.anuke.mindustry.type;
|
||||||
|
|
||||||
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
|
|
||||||
|
/** Represents a blank type of content that has an error. Replaces anything that failed to parse. */
|
||||||
|
public class ErrorContent extends Content{
|
||||||
|
@Override
|
||||||
|
public ContentType getContentType(){
|
||||||
|
return ContentType.error;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import io.anuke.arc.collection.*;
|
|||||||
import io.anuke.arc.graphics.*;
|
import io.anuke.arc.graphics.*;
|
||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.ui.*;
|
import io.anuke.mindustry.ui.*;
|
||||||
import io.anuke.mindustry.world.blocks.*;
|
import io.anuke.mindustry.world.blocks.*;
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import io.anuke.arc.scene.ui.layout.*;
|
|||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.ui.*;
|
import io.anuke.mindustry.ui.*;
|
||||||
|
|
||||||
public class Liquid extends UnlockableContent{
|
public class Liquid extends UnlockableContent{
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import io.anuke.arc.graphics.Color;
|
|||||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||||
import io.anuke.arc.scene.ui.layout.Table;
|
import io.anuke.arc.scene.ui.layout.Table;
|
||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.type.Player;
|
import io.anuke.mindustry.entities.type.Player;
|
||||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||||
import io.anuke.mindustry.graphics.Pal;
|
import io.anuke.mindustry.graphics.Pal;
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ public interface Publishable{
|
|||||||
/** @return the tag that this content has. e.g. 'schematic' or 'map'. */
|
/** @return the tag that this content has. e.g. 'schematic' or 'map'. */
|
||||||
String steamTag();
|
String steamTag();
|
||||||
/** @return a folder with everything needed for this piece of content in it; does not need to be a copy. */
|
/** @return a folder with everything needed for this piece of content in it; does not need to be a copy. */
|
||||||
FileHandle createSteamFolder(String id);
|
Fi createSteamFolder(String id);
|
||||||
/** @return a preview file PNG. */
|
/** @return a preview file PNG. */
|
||||||
FileHandle createSteamPreview(String id);
|
Fi createSteamPreview(String id);
|
||||||
/** @return any extra tags to add to this item.*/
|
/** @return any extra tags to add to this item.*/
|
||||||
default Array<String> extraTags(){
|
default Array<String> extraTags(){
|
||||||
return new Array<>(0);
|
return new Array<>(0);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import io.anuke.arc.math.*;
|
|||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.Effects.*;
|
import io.anuke.mindustry.entities.Effects.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.type;
|
|||||||
|
|
||||||
import io.anuke.arc.func.*;
|
import io.anuke.arc.func.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.entities.traits.*;
|
import io.anuke.mindustry.entities.traits.*;
|
||||||
|
|
||||||
public class TypeID extends MappableContent{
|
public class TypeID extends MappableContent{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import io.anuke.arc.graphics.g2d.*;
|
|||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.anuke.mindustry.type;
|
package io.anuke.mindustry.type;
|
||||||
|
|
||||||
import io.anuke.mindustry.ctype.Content;
|
import io.anuke.mindustry.ctype.Content;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
|
|
||||||
//currently unimplemented, see trello for implementation plans
|
//currently unimplemented, see trello for implementation plans
|
||||||
public class WeatherEvent extends Content{
|
public class WeatherEvent extends Content{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import io.anuke.arc.graphics.g2d.*;
|
|||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.ArcAnnotate.*;
|
import io.anuke.arc.util.ArcAnnotate.*;
|
||||||
import io.anuke.mindustry.content.*;
|
import io.anuke.mindustry.content.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||||
import io.anuke.mindustry.game.EventType.*;
|
import io.anuke.mindustry.game.EventType.*;
|
||||||
import io.anuke.mindustry.game.*;
|
import io.anuke.mindustry.game.*;
|
||||||
@@ -172,8 +173,8 @@ public class Zone extends UnlockableContent{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init(){
|
public void init(){
|
||||||
if(generator instanceof MapGenerator && mod != null){
|
if(generator instanceof MapGenerator && minfo.mod != null){
|
||||||
((MapGenerator)generator).removePrefix(mod.name);
|
((MapGenerator)generator).removePrefix(minfo.mod.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
generator.init(loadout);
|
generator.init(loadout);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import static io.anuke.mindustry.gen.Tex.*;
|
|||||||
public class Styles{
|
public class Styles{
|
||||||
public static Drawable black, black9, black8, black6, black3, none, flatDown, flatOver;
|
public static Drawable black, black9, black8, black6, black3, none, flatDown, flatOver;
|
||||||
public static ButtonStyle defaultb, waveb;
|
public static ButtonStyle defaultb, waveb;
|
||||||
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet;
|
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt;
|
||||||
public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali;
|
public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali;
|
||||||
public static ScrollPaneStyle defaultPane, horizontalPane, smallPane;
|
public static ScrollPaneStyle defaultPane, horizontalPane, smallPane;
|
||||||
public static KeybindDialogStyle defaultKeybindDialog;
|
public static KeybindDialogStyle defaultKeybindDialog;
|
||||||
@@ -110,6 +110,14 @@ public class Styles{
|
|||||||
fontColor = Color.white;
|
fontColor = Color.white;
|
||||||
disabledFontColor = Color.gray;
|
disabledFontColor = Color.gray;
|
||||||
}};
|
}};
|
||||||
|
transt = new TextButtonStyle(){{
|
||||||
|
down = flatDown;
|
||||||
|
up = none;
|
||||||
|
over = flatOver;
|
||||||
|
font = Fonts.def;
|
||||||
|
fontColor = Color.white;
|
||||||
|
disabledFontColor = Color.gray;
|
||||||
|
}};
|
||||||
clearTogglet = new TextButtonStyle(){{
|
clearTogglet = new TextButtonStyle(){{
|
||||||
font = Fonts.def;
|
font = Fonts.def;
|
||||||
fontColor = Color.white;
|
fontColor = Color.white;
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import io.anuke.arc.util.*;
|
|||||||
import io.anuke.mindustry.*;
|
import io.anuke.mindustry.*;
|
||||||
import io.anuke.mindustry.core.GameState.*;
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
import io.anuke.mindustry.ctype.*;
|
import io.anuke.mindustry.ctype.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.gen.*;
|
import io.anuke.mindustry.gen.*;
|
||||||
import io.anuke.mindustry.graphics.*;
|
import io.anuke.mindustry.graphics.*;
|
||||||
import io.anuke.mindustry.type.*;
|
|
||||||
import io.anuke.mindustry.ui.*;
|
import io.anuke.mindustry.ui.*;
|
||||||
|
|
||||||
public class DatabaseDialog extends FloatingDialog{
|
public class DatabaseDialog extends FloatingDialog{
|
||||||
|
|||||||
@@ -18,20 +18,20 @@ import java.util.*;
|
|||||||
import static io.anuke.mindustry.Vars.platform;
|
import static io.anuke.mindustry.Vars.platform;
|
||||||
|
|
||||||
public class FileChooser extends FloatingDialog{
|
public class FileChooser extends FloatingDialog{
|
||||||
private static final FileHandle homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath());
|
private static final Fi homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath());
|
||||||
private static FileHandle lastDirectory = homeDirectory;
|
private static Fi lastDirectory = homeDirectory;
|
||||||
|
|
||||||
private Table files;
|
private Table files;
|
||||||
private FileHandle directory = lastDirectory;
|
private Fi directory = lastDirectory;
|
||||||
private ScrollPane pane;
|
private ScrollPane pane;
|
||||||
private TextField navigation, filefield;
|
private TextField navigation, filefield;
|
||||||
private TextButton ok;
|
private TextButton ok;
|
||||||
private FileHistory stack = new FileHistory();
|
private FileHistory stack = new FileHistory();
|
||||||
private Boolf<FileHandle> filter;
|
private Boolf<Fi> filter;
|
||||||
private Cons<FileHandle> selectListener;
|
private Cons<Fi> selectListener;
|
||||||
private boolean open;
|
private boolean open;
|
||||||
|
|
||||||
public FileChooser(String title, Boolf<FileHandle> filter, boolean open, Cons<FileHandle> result){
|
public FileChooser(String title, Boolf<Fi> filter, boolean open, Cons<Fi> result){
|
||||||
super(title);
|
super(title);
|
||||||
setFillParent(true);
|
setFillParent(true);
|
||||||
this.open = open;
|
this.open = open;
|
||||||
@@ -154,8 +154,8 @@ public class FileChooser extends FloatingDialog{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private FileHandle[] getFileNames(){
|
private Fi[] getFileNames(){
|
||||||
FileHandle[] handles = directory.list(file -> !file.getName().startsWith("."));
|
Fi[] handles = directory.list(file -> !file.getName().startsWith("."));
|
||||||
|
|
||||||
Arrays.sort(handles, (a, b) -> {
|
Arrays.sort(handles, (a, b) -> {
|
||||||
if(a.isDirectory() && !b.isDirectory()) return -1;
|
if(a.isDirectory() && !b.isDirectory()) return -1;
|
||||||
@@ -183,7 +183,7 @@ public class FileChooser extends FloatingDialog{
|
|||||||
|
|
||||||
files.clearChildren();
|
files.clearChildren();
|
||||||
files.top().left();
|
files.top().left();
|
||||||
FileHandle[] names = getFileNames();
|
Fi[] names = getFileNames();
|
||||||
|
|
||||||
Image upimage = new Image(Icon.folderParentSmall);
|
Image upimage = new Image(Icon.folderParentSmall);
|
||||||
TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet);
|
TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet);
|
||||||
@@ -204,7 +204,7 @@ public class FileChooser extends FloatingDialog{
|
|||||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||||
group.setMinCheckCount(0);
|
group.setMinCheckCount(0);
|
||||||
|
|
||||||
for(FileHandle file : names){
|
for(Fi file : names){
|
||||||
if(!file.isDirectory() && !filter.get(file)) continue; //skip non-filtered files
|
if(!file.isDirectory() && !filter.get(file)) continue; //skip non-filtered files
|
||||||
|
|
||||||
String filename = file.name();
|
String filename = file.name();
|
||||||
@@ -255,14 +255,14 @@ public class FileChooser extends FloatingDialog{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class FileHistory{
|
public class FileHistory{
|
||||||
private Array<FileHandle> history = new Array<>();
|
private Array<Fi> history = new Array<>();
|
||||||
private int index;
|
private int index;
|
||||||
|
|
||||||
public FileHistory(){
|
public FileHistory(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void push(FileHandle file){
|
public void push(Fi file){
|
||||||
if(index != history.size) history.truncate(index);
|
if(index != history.size) history.truncate(index);
|
||||||
history.add(file);
|
history.add(file);
|
||||||
index++;
|
index++;
|
||||||
@@ -296,7 +296,7 @@ public class FileChooser extends FloatingDialog{
|
|||||||
|
|
||||||
System.out.println("\n\n\n\n\n\n");
|
System.out.println("\n\n\n\n\n\n");
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for(FileHandle file : history){
|
for(Fi file : history){
|
||||||
i++;
|
i++;
|
||||||
if(index == i){
|
if(index == i){
|
||||||
System.out.println("[[" + file.toString() + "]]");
|
System.out.println("[[" + file.toString() + "]]");
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public class LoadDialog extends FloatingDialog{
|
|||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
try{
|
try{
|
||||||
FileHandle file = Core.files.local("save-" + slot.getName() + "." + saveExtension);
|
Fi file = Core.files.local("save-" + slot.getName() + "." + saveExtension);
|
||||||
slot.exportFile(file);
|
slot.exportFile(file);
|
||||||
platform.shareFile(file);
|
platform.shareFile(file);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.ui.dialogs;
|
|||||||
|
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.Net.*;
|
import io.anuke.arc.Net.*;
|
||||||
import io.anuke.arc.collection.*;
|
|
||||||
import io.anuke.arc.files.*;
|
import io.anuke.arc.files.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.io.*;
|
import io.anuke.arc.util.io.*;
|
||||||
@@ -47,7 +46,7 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
ui.loadfrag.hide();
|
ui.loadfrag.hide();
|
||||||
}else{
|
}else{
|
||||||
try{
|
try{
|
||||||
FileHandle file = tmpDirectory.child(text.replace("/", "") + ".zip");
|
Fi file = tmpDirectory.child(text.replace("/", "") + ".zip");
|
||||||
Streams.copyStream(result.getResultAsStream(), file.write(false));
|
Streams.copyStream(result.getResultAsStream(), file.write(false));
|
||||||
mods.importMod(file);
|
mods.importMod(file);
|
||||||
file.delete();
|
file.delete();
|
||||||
@@ -75,7 +74,7 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
hidden(() -> {
|
hidden(() -> {
|
||||||
if(mods.requiresReload()){
|
if(mods.requiresReload()){
|
||||||
ui.loadAnd("$reloading", () -> {
|
ui.loadAnd("$reloading", () -> {
|
||||||
mods.all().each(mod -> {
|
mods.eachEnabled(mod -> {
|
||||||
if(mod.hasUnmetDependencies()){
|
if(mod.hasUnmetDependencies()){
|
||||||
ui.showErrorMessage(Core.bundle.format("mod.nowdisabled", mod.name, mod.missingDependencies.toString(", ")));
|
ui.showErrorMessage(Core.bundle.format("mod.nowdisabled", mod.name, mod.missingDependencies.toString(", ")));
|
||||||
}
|
}
|
||||||
@@ -107,14 +106,13 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
cont.defaults().width(mobile ? 500 : 560f).pad(4);
|
cont.defaults().width(mobile ? 500 : 560f).pad(4);
|
||||||
cont.add("$mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center);
|
cont.add("$mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center);
|
||||||
cont.row();
|
cont.row();
|
||||||
if(!(mods.all().isEmpty() && mods.disabled().isEmpty())){
|
if(!mods.list().isEmpty()){
|
||||||
cont.pane(table -> {
|
cont.pane(table -> {
|
||||||
table.margin(10f).top();
|
table.margin(10f).top();
|
||||||
Array<LoadedMod> all = Array.withArrays(mods.all(), mods.disabled());
|
|
||||||
|
|
||||||
boolean anyDisabled = false;
|
boolean anyDisabled = false;
|
||||||
for(LoadedMod mod : all){
|
for(LoadedMod mod : mods.list()){
|
||||||
if(!mod.enabled() && !anyDisabled && mods.all().size > 0){
|
if(!mod.enabled() && !anyDisabled && mods.list().size > 0){
|
||||||
anyDisabled = true;
|
anyDisabled = true;
|
||||||
table.row();
|
table.row();
|
||||||
table.addImage().growX().height(4f).pad(6f).color(Pal.gray);
|
table.addImage().growX().height(4f).pad(6f).color(Pal.gray);
|
||||||
@@ -167,6 +165,9 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
}else if(mod.hasUnmetDependencies()){
|
}else if(mod.hasUnmetDependencies()){
|
||||||
t.labelWrap(Core.bundle.format("mod.missingdependencies", mod.missingDependencies.toString(", "))).growX();
|
t.labelWrap(Core.bundle.format("mod.missingdependencies", mod.missingDependencies.toString(", "))).growX();
|
||||||
t.row();
|
t.row();
|
||||||
|
}else if(mod.hasContentErrors()){
|
||||||
|
t.labelWrap("$mod.erroredcontent").growX();
|
||||||
|
t.row();
|
||||||
}
|
}
|
||||||
}).width(mobile ? 430f : 500f);
|
}).width(mobile ? 430f : 500f);
|
||||||
table.row();
|
table.row();
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
|||||||
Core.settings.putAll(map);
|
Core.settings.putAll(map);
|
||||||
Core.settings.save();
|
Core.settings.save();
|
||||||
|
|
||||||
for(FileHandle file : dataDirectory.list()){
|
for(Fi file : dataDirectory.list()){
|
||||||
file.deleteDirectory();
|
file.deleteDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
|||||||
|
|
||||||
t.addButton("$data.export", style, () -> {
|
t.addButton("$data.export", style, () -> {
|
||||||
if(ios){
|
if(ios){
|
||||||
FileHandle file = Core.files.local("mindustry-data-export.zip");
|
Fi file = Core.files.local("mindustry-data-export.zip");
|
||||||
try{
|
try{
|
||||||
data.exportData(file);
|
data.exportData(file);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public class BlockInventoryFragment extends Fragment{
|
|||||||
int removed = tile.block().removeStack(tile, item, amount);
|
int removed = tile.block().removeStack(tile, item, amount);
|
||||||
|
|
||||||
player.addItem(item, removed);
|
player.addItem(item, removed);
|
||||||
|
Events.fire(new WithdrawEvent(tile, player, item, amount));
|
||||||
for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
|
for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
|
||||||
Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.drawx(), tile.drawy(), player));
|
Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.drawx(), tile.drawy(), player));
|
||||||
}
|
}
|
||||||
@@ -100,7 +101,7 @@ public class BlockInventoryFragment extends Fragment{
|
|||||||
holding = false;
|
holding = false;
|
||||||
holdTime = 0f;
|
holdTime = 0f;
|
||||||
|
|
||||||
Events.fire(new WithdrawEvent());
|
if(net.client()) Events.fire(new WithdrawEvent(tile, player, lastItem, amount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +154,7 @@ public class BlockInventoryFragment extends Fragment{
|
|||||||
lastItem = item;
|
lastItem = item;
|
||||||
holding = true;
|
holding = true;
|
||||||
holdTime = 0f;
|
holdTime = 0f;
|
||||||
Events.fire(new WithdrawEvent());
|
if(net.client()) Events.fire(new WithdrawEvent(tile, player, item, amount));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import io.anuke.arc.scene.ui.ImageButton.*;
|
|||||||
import io.anuke.arc.scene.ui.layout.*;
|
import io.anuke.arc.scene.ui.layout.*;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.mindustry.core.GameState.*;
|
import io.anuke.mindustry.core.GameState.*;
|
||||||
|
import io.anuke.mindustry.ctype.ContentType;
|
||||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
import io.anuke.mindustry.entities.type.*;
|
import io.anuke.mindustry.entities.type.*;
|
||||||
|
|||||||
@@ -88,11 +88,11 @@ public class MenuFragment extends Fragment{
|
|||||||
container.defaults().size(size).pad(5).padTop(4f);
|
container.defaults().size(size).pad(5).padTop(4f);
|
||||||
|
|
||||||
MobileButton
|
MobileButton
|
||||||
play = new MobileButton(Icon.play2, "$campaign", ui.deploy::show),
|
play = new MobileButton(Icon.play2, "$campaign", () -> checkPlay(ui.deploy::show)),
|
||||||
custom = new MobileButton(Icon.playCustom, "$customgame", ui.custom::show),
|
custom = new MobileButton(Icon.playCustom, "$customgame", () -> checkPlay(ui.custom::show)),
|
||||||
maps = new MobileButton(Icon.load, "$loadgame", ui.load::show),
|
maps = new MobileButton(Icon.load, "$loadgame", () -> checkPlay(ui.load::show)),
|
||||||
join = new MobileButton(Icon.add, "$joingame", ui.join::show),
|
join = new MobileButton(Icon.add, "$joingame", () -> checkPlay(ui.join::show)),
|
||||||
editor = new MobileButton(Icon.editor, "$editor", ui.maps::show),
|
editor = new MobileButton(Icon.editor, "$editor", () -> checkPlay(ui.maps::show)),
|
||||||
tools = new MobileButton(Icon.tools, "$settings", ui.settings::show),
|
tools = new MobileButton(Icon.tools, "$settings", ui.settings::show),
|
||||||
mods = new MobileButton(Icon.wiki, "$mods", ui.mods::show),
|
mods = new MobileButton(Icon.wiki, "$mods", ui.mods::show),
|
||||||
donate = new MobileButton(Icon.link, "$website", () -> Core.net.openURI("https://anuke.itch.io/mindustry")),
|
donate = new MobileButton(Icon.link, "$website", () -> Core.net.openURI("https://anuke.itch.io/mindustry")),
|
||||||
@@ -153,13 +153,13 @@ public class MenuFragment extends Fragment{
|
|||||||
|
|
||||||
buttons(t,
|
buttons(t,
|
||||||
new Buttoni("$play", Icon.play2Small,
|
new Buttoni("$play", Icon.play2Small,
|
||||||
new Buttoni("$campaign", Icon.play2Small, ui.deploy::show),
|
new Buttoni("$campaign", Icon.play2Small, () -> checkPlay(ui.deploy::show)),
|
||||||
new Buttoni("$joingame", Icon.addSmall, ui.join::show),
|
new Buttoni("$joingame", Icon.addSmall, () -> checkPlay(ui.join::show)),
|
||||||
new Buttoni("$customgame", Icon.editorSmall, ui.custom::show),
|
new Buttoni("$customgame", Icon.editorSmall, () -> checkPlay(ui.custom::show)),
|
||||||
new Buttoni("$loadgame", Icon.loadSmall, ui.load::show),
|
new Buttoni("$loadgame", Icon.loadSmall, () -> checkPlay(ui.load::show)),
|
||||||
new Buttoni("$tutorial", Icon.infoSmall, control::playTutorial)
|
new Buttoni("$tutorial", Icon.infoSmall, () -> checkPlay(control::playTutorial))
|
||||||
),
|
),
|
||||||
new Buttoni("$editor", Icon.editorSmall, ui.maps::show), steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null,
|
new Buttoni("$editor", Icon.editorSmall, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null,
|
||||||
new Buttoni(Core.bundle.get("mods") + "\n" + Core.bundle.get("mods.alpha"), Icon.wikiSmall, ui.mods::show),
|
new Buttoni(Core.bundle.get("mods") + "\n" + Core.bundle.get("mods.alpha"), Icon.wikiSmall, ui.mods::show),
|
||||||
//not enough space for this button
|
//not enough space for this button
|
||||||
//new Buttoni("$schematics", Icon.pasteSmall, ui.schematics::show),
|
//new Buttoni("$schematics", Icon.pasteSmall, ui.schematics::show),
|
||||||
@@ -180,6 +180,14 @@ public class MenuFragment extends Fragment{
|
|||||||
}).width(width).growY();
|
}).width(width).growY();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkPlay(Runnable run){
|
||||||
|
if(!mods.hasContentErrors()){
|
||||||
|
run.run();
|
||||||
|
}else{
|
||||||
|
ui.showInfo("$mod.noerrorplay");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void fadeInMenu(){
|
private void fadeInMenu(){
|
||||||
submenu.clearActions();
|
submenu.clearActions();
|
||||||
submenu.actions(Actions.alpha(1f, 0.15f, Interpolation.fade));
|
submenu.actions(Actions.alpha(1f, 0.15f, Interpolation.fade));
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user