Merge branch 'master' into crater
# Conflicts: # core/assets/sprites/block_colors.png # core/assets/sprites/sprites.atlas # core/assets/sprites/sprites.png # core/assets/sprites/sprites3.png # core/assets/sprites/sprites5.png # core/src/mindustry/world/modules/ItemModule.java
@@ -23,11 +23,13 @@ First, make sure you have [JDK 8](https://adoptopenjdk.net/) installed. Open a t
|
|||||||
|
|
||||||
_Running:_ `gradlew desktop:run`
|
_Running:_ `gradlew desktop:run`
|
||||||
_Building:_ `gradlew desktop:dist`
|
_Building:_ `gradlew desktop:dist`
|
||||||
|
_Sprite Packing:_ `gradlew tools:pack`
|
||||||
|
|
||||||
#### Linux/Mac OS
|
#### Linux/Mac OS
|
||||||
|
|
||||||
_Running:_ `./gradlew desktop:run`
|
_Running:_ `./gradlew desktop:run`
|
||||||
_Building:_ `./gradlew desktop:dist`
|
_Building:_ `./gradlew desktop:dist`
|
||||||
|
_Sprite Packing:_ `./gradlew tools:pack`
|
||||||
|
|
||||||
#### Server
|
#### Server
|
||||||
|
|
||||||
|
|||||||
@@ -177,6 +177,7 @@ public class AndroidLauncher extends AndroidApplication{
|
|||||||
}
|
}
|
||||||
//create marker
|
//create marker
|
||||||
Core.files.local("files_moved").writeString("files moved to " + data);
|
Core.files.local("files_moved").writeString("files moved to " + data);
|
||||||
|
Core.files.local("files_moved_103").writeString("files moved again");
|
||||||
Log.info("Files moved.");
|
Log.info("Files moved.");
|
||||||
}catch(Throwable t){
|
}catch(Throwable t){
|
||||||
Log.err("Failed to move files!");
|
Log.err("Failed to move files!");
|
||||||
|
|||||||
@@ -3,6 +3,36 @@ package mindustry.annotations;
|
|||||||
import java.lang.annotation.*;
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
public class Annotations{
|
public class Annotations{
|
||||||
|
//region entity interfaces
|
||||||
|
|
||||||
|
/** Indicates multiple inheritance on a component type. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface Depends{
|
||||||
|
Class[] value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates that a component def is present on all entities. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface BaseComponent{
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates an entity definition. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface EntityDef{
|
||||||
|
Class[] value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates an internal interface for entity components. */
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface EntityInterface{
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region misc. utility
|
||||||
|
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@@ -29,6 +59,9 @@ public class Annotations{
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region struct
|
||||||
|
|
||||||
/** Marks a class as a special value type struct. Class name must end in 'Struct'. */
|
/** Marks a class as a special value type struct. Class name must end in 'Struct'. */
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@@ -44,6 +77,9 @@ public class Annotations{
|
|||||||
int value();
|
int value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
//region remote
|
||||||
|
|
||||||
public enum PacketPriority{
|
public enum PacketPriority{
|
||||||
/** Gets put in a queue and processed if not connected. */
|
/** Gets put in a queue and processed if not connected. */
|
||||||
normal,
|
normal,
|
||||||
@@ -138,4 +174,6 @@ public class Annotations{
|
|||||||
public @interface ReadClass{
|
public @interface ReadClass{
|
||||||
Class<?> value();
|
Class<?> value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,19 @@
|
|||||||
package mindustry.annotations;
|
package mindustry.annotations;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import com.sun.source.util.*;
|
||||||
|
import mindustry.annotations.util.*;
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
import javax.annotation.processing.*;
|
||||||
import javax.lang.model.*;
|
import javax.lang.model.*;
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.*;
|
||||||
import javax.lang.model.util.*;
|
import javax.lang.model.util.*;
|
||||||
|
import javax.tools.Diagnostic.*;
|
||||||
|
import javax.tools.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.lang.annotation.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||||
@@ -15,8 +25,11 @@ public abstract class BaseProcessor extends AbstractProcessor{
|
|||||||
public static Elements elementu;
|
public static Elements elementu;
|
||||||
public static Filer filer;
|
public static Filer filer;
|
||||||
public static Messager messager;
|
public static Messager messager;
|
||||||
|
public static Trees trees;
|
||||||
|
|
||||||
protected int round;
|
protected int round;
|
||||||
|
protected int rounds = 1;
|
||||||
|
protected RoundEnvironment env;
|
||||||
|
|
||||||
public static String getMethodName(Element element){
|
public static String getMethodName(Element element){
|
||||||
return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName();
|
return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName();
|
||||||
@@ -27,19 +40,80 @@ public abstract class BaseProcessor extends AbstractProcessor{
|
|||||||
|| type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char");
|
|| type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public static void write(TypeSpec.Builder builder) throws Exception{
|
||||||
public synchronized void init(ProcessingEnvironment processingEnv){
|
write(builder, null);
|
||||||
super.init(processingEnv);
|
}
|
||||||
|
|
||||||
typeu = processingEnv.getTypeUtils();
|
public static void write(TypeSpec.Builder builder, Array<String> imports) throws Exception{
|
||||||
elementu = processingEnv.getElementUtils();
|
JavaFile file = JavaFile.builder(packageName, builder.build()).skipJavaLangImports(true).build();
|
||||||
filer = processingEnv.getFiler();
|
|
||||||
messager = processingEnv.getMessager();
|
if(imports != null){
|
||||||
|
String rawSource = file.toString();
|
||||||
|
Array<String> result = new Array<>();
|
||||||
|
for (String s : rawSource.split("\n", -1)) {
|
||||||
|
result.add(s);
|
||||||
|
if (s.startsWith("package ")) {
|
||||||
|
result.add("");
|
||||||
|
for (String i : imports) {
|
||||||
|
result.add(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
String out = result.toString("\n");
|
||||||
|
JavaFileObject object = filer.createSourceFile(file.packageName + "." + file.typeSpec.name, file.typeSpec.originatingElements.toArray(new Element[0]));
|
||||||
|
OutputStream stream = object.openOutputStream();
|
||||||
|
stream.write(out.getBytes());
|
||||||
|
stream.close();
|
||||||
|
}else{
|
||||||
|
file.writeTo(filer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Stype> types(Class<? extends Annotation> type){
|
||||||
|
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof TypeElement)
|
||||||
|
.map(e -> new Stype((TypeElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Svar> fields(Class<? extends Annotation> type){
|
||||||
|
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof VariableElement)
|
||||||
|
.map(e -> new Svar((VariableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Smethod> methods(Class<? extends Annotation> type){
|
||||||
|
return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof ExecutableElement)
|
||||||
|
.map(e -> new Smethod((ExecutableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void err(String message){
|
||||||
|
messager.printMessage(Kind.ERROR, message);
|
||||||
|
Log.err("[CODEGEN ERROR] " +message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void err(String message, Element elem){
|
||||||
|
messager.printMessage(Kind.ERROR, message, elem);
|
||||||
|
Log.err("[CODEGEN ERROR] " + message + ": " + elem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void err(String message, Selement elem){
|
||||||
|
err(message, elem.e);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public synchronized void init(ProcessingEnvironment env){
|
||||||
|
super.init(env);
|
||||||
|
|
||||||
|
trees = Trees.instance(env);
|
||||||
|
typeu = env.getTypeUtils();
|
||||||
|
elementu = env.getElementUtils();
|
||||||
|
filer = env.getFiler();
|
||||||
|
messager = env.getMessager();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
||||||
if(round++ != 0) return false; //only process 1 round
|
if(round++ >= rounds) return false; //only process 1 round
|
||||||
|
this.env = roundEnv;
|
||||||
try{
|
try{
|
||||||
process(roundEnv);
|
process(roundEnv);
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import javax.tools.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@SupportedAnnotationTypes("mindustry.annotations.Annotations.StyleDefaults")
|
@SupportedAnnotationTypes("mindustry.annotations.Annotations.StyleDefaults")
|
||||||
public class AssetsAnnotationProcessor extends BaseProcessor{
|
public class AssetsProcess extends BaseProcessor{
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -18,7 +18,7 @@ import java.lang.annotation.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@SupportedAnnotationTypes({"java.lang.Override"})
|
@SupportedAnnotationTypes({"java.lang.Override"})
|
||||||
public class CallSuperAnnotationProcessor extends AbstractProcessor{
|
public class CallSuperProcess extends AbstractProcessor{
|
||||||
private Trees trees;
|
private Trees trees;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -122,6 +122,7 @@ public class CallSuperAnnotationProcessor extends AbstractProcessor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
for(Symbol s : it){
|
for(Symbol s : it){
|
||||||
|
|
||||||
if(s instanceof MethodSymbol){
|
if(s instanceof MethodSymbol){
|
||||||
MethodSymbol ms = (MethodSymbol)s;
|
MethodSymbol ms = (MethodSymbol)s;
|
||||||
|
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
package mindustry.annotations.impl;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import com.squareup.javapoet.TypeSpec.*;
|
||||||
|
import com.sun.source.tree.*;
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
import mindustry.annotations.util.*;
|
||||||
|
|
||||||
|
import javax.annotation.processing.*;
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.type.*;
|
||||||
|
|
||||||
|
@SupportedAnnotationTypes({
|
||||||
|
"mindustry.annotations.Annotations.EntityDef",
|
||||||
|
"mindustry.annotations.Annotations.EntityInterface",
|
||||||
|
"mindustry.annotations.Annotations.BaseComponent"
|
||||||
|
})
|
||||||
|
public class EntityProcess extends BaseProcessor{
|
||||||
|
Array<Definition> definitions = new Array<>();
|
||||||
|
Array<Stype> baseComponents;
|
||||||
|
ObjectMap<Stype, Array<Stype>> componentDependencies = new ObjectMap<>();
|
||||||
|
ObjectMap<Stype, Array<Stype>> defComponents = new ObjectMap<>();
|
||||||
|
ObjectSet<String> imports = new ObjectSet<>();
|
||||||
|
|
||||||
|
{
|
||||||
|
rounds = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(RoundEnvironment env) throws Exception{
|
||||||
|
|
||||||
|
//round 1: get component classes and generate interfaces for them
|
||||||
|
if(round == 1){
|
||||||
|
baseComponents = types(BaseComponent.class);
|
||||||
|
Array<Stype> allDefs = types(EntityDef.class);
|
||||||
|
|
||||||
|
ObjectSet<Stype> allComponents = new ObjectSet<>();
|
||||||
|
|
||||||
|
//find all components used...
|
||||||
|
for(Stype type : allDefs){
|
||||||
|
allComponents.addAll(allComponents(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
//add all components w/ dependencies
|
||||||
|
allComponents.addAll(types(Depends.class).map(s -> Array.withArrays(getDependencies(s), s)).flatten());
|
||||||
|
|
||||||
|
//add component imports
|
||||||
|
for(Stype comp : allComponents){
|
||||||
|
imports.addAll(getImports(comp.e));
|
||||||
|
}
|
||||||
|
|
||||||
|
//create component interfaces
|
||||||
|
for(Stype component : allComponents){
|
||||||
|
TypeSpec.Builder inter = TypeSpec.interfaceBuilder(interfaceName(component)).addModifiers(Modifier.PUBLIC).addAnnotation(EntityInterface.class);
|
||||||
|
|
||||||
|
//implement extra interfaces these components may have, e.g. position
|
||||||
|
for(Stype extraInterface : component.interfaces()){
|
||||||
|
inter.addSuperinterface(extraInterface.mirror());
|
||||||
|
}
|
||||||
|
|
||||||
|
//implement super interfaces
|
||||||
|
Array<Stype> depends = getDependencies(component);
|
||||||
|
for(Stype type : depends){
|
||||||
|
inter.addSuperinterface(ClassName.get(packageName, interfaceName(type)));
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.is(Modifier.TRANSIENT))){
|
||||||
|
String cname = Strings.capitalize(field.name());
|
||||||
|
//getter
|
||||||
|
inter.addMethod(MethodSpec.methodBuilder("get" + cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC).returns(field.tname()).build());
|
||||||
|
//setter
|
||||||
|
if(!field.is(Modifier.FINAL)) inter.addMethod(MethodSpec.methodBuilder("set" + cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC).addParameter(field.tname(), field.name()).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
//add utility methods to interface
|
||||||
|
for(Smethod method : component.methods()){
|
||||||
|
inter.addMethod(MethodSpec.methodBuilder(method.name())
|
||||||
|
.addExceptions(method.thrownt())
|
||||||
|
.addTypeVariables(method.typeVariables().map(TypeVariableName::get))
|
||||||
|
.returns(method.ret().toString().equals("void") ? TypeName.VOID : method.retn())
|
||||||
|
.addParameters(method.params().map(v -> ParameterSpec.builder(v.tname(), v.name())
|
||||||
|
.build())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build());
|
||||||
|
}
|
||||||
|
|
||||||
|
write(inter);
|
||||||
|
}
|
||||||
|
|
||||||
|
//look at each definition
|
||||||
|
for(Stype type : allDefs){
|
||||||
|
if(!type.name().endsWith("Def")){
|
||||||
|
err("All entity def names must end with 'Def'", type.e);
|
||||||
|
}
|
||||||
|
String name = type.name().replace("Def", "Gen"); //TODO remove 'gen'
|
||||||
|
TypeSpec.Builder builder = TypeSpec.classBuilder(name).addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||||
|
|
||||||
|
Array<Stype> components = allComponents(type);
|
||||||
|
ObjectMap<String, Array<Smethod>> methods = new ObjectMap<>();
|
||||||
|
|
||||||
|
//add all components
|
||||||
|
for(Stype comp : components){
|
||||||
|
|
||||||
|
//write fields to the class; ignoring transient ones
|
||||||
|
Array<Svar> fields = comp.fields().select(f -> !f.is(Modifier.TRANSIENT));
|
||||||
|
for(Svar f : fields){
|
||||||
|
VariableTree tree = f.tree();
|
||||||
|
FieldSpec.Builder fbuilder = FieldSpec.builder(f.tname(), f.name());
|
||||||
|
//add initializer if it exists
|
||||||
|
if(tree.getInitializer() != null){
|
||||||
|
fbuilder.initializer(tree.getInitializer().toString());
|
||||||
|
}
|
||||||
|
builder.addField(fbuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
//get all utility methods from components
|
||||||
|
for(Smethod elem : comp.methods()){
|
||||||
|
methods.getOr(elem.toString(), Array::new).add(elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add all methods from components
|
||||||
|
for(ObjectMap.Entry<String, Array<Smethod>> entry : methods){
|
||||||
|
//representative method
|
||||||
|
Smethod first = entry.value.first();
|
||||||
|
//build method using same params/returns
|
||||||
|
MethodSpec.Builder mbuilder = MethodSpec.methodBuilder(first.name()).addModifiers(Modifier.PUBLIC, Modifier.FINAL);
|
||||||
|
mbuilder.addTypeVariables(first.typeVariables().map(TypeVariableName::get));
|
||||||
|
mbuilder.returns(first.retn());
|
||||||
|
mbuilder.addExceptions(first.thrownt());
|
||||||
|
|
||||||
|
for(Svar var : first.params()){
|
||||||
|
mbuilder.addParameter(var.tname(), var.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
//only write the block if it's a void method with several entries
|
||||||
|
boolean writeBlock = first.ret().toString().equals("void") && entry.value.size > 1;
|
||||||
|
|
||||||
|
if(entry.value.first().is(Modifier.ABSTRACT) && entry.value.size == 1){
|
||||||
|
err(entry.value.first().up().getSimpleName() + " declares an abstract method. This method must be implemented in another component", entry.value.first());
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Smethod elem : entry.value){
|
||||||
|
if(elem.is(Modifier.ABSTRACT)) continue;
|
||||||
|
|
||||||
|
//get all statements in the method, copy them over
|
||||||
|
MethodTree methodTree = elem.tree();
|
||||||
|
BlockTree blockTree = methodTree.getBody();
|
||||||
|
String str = blockTree.toString();
|
||||||
|
//name for code blocks in the methods
|
||||||
|
String blockName = elem.up().getSimpleName().toString().toLowerCase().replace("comp", "");
|
||||||
|
|
||||||
|
//skip empty blocks
|
||||||
|
if(str.replace("{", "").replace("\n", "").replace("}", "").replace("\t", "").replace(" ", "").isEmpty()){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//wrap scope to prevent variable leakage
|
||||||
|
if(writeBlock){
|
||||||
|
//replace return; with block break
|
||||||
|
str = str.replace("return;", "break " + blockName + ";");
|
||||||
|
mbuilder.addCode(blockName + ": {\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
//trim block
|
||||||
|
str = str.substring(2, str.length() - 1);
|
||||||
|
|
||||||
|
//make sure to remove braces here
|
||||||
|
mbuilder.addCode(str);
|
||||||
|
|
||||||
|
//end scope
|
||||||
|
if(writeBlock) mbuilder.addCode("}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.addMethod(mbuilder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
definitions.add(new Definition(builder, type));
|
||||||
|
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//round 2: generate actual classes and implement interfaces
|
||||||
|
Array<Stype> interfaces = types(EntityInterface.class);
|
||||||
|
|
||||||
|
//implement each definition
|
||||||
|
for(Definition def : definitions){
|
||||||
|
Array<Stype> components = allComponents(def.base);
|
||||||
|
|
||||||
|
//get interface for each component
|
||||||
|
for(Stype comp : components){
|
||||||
|
//implement the interface
|
||||||
|
Stype inter = interfaces.find(i -> i.name().equals(interfaceName(comp)));
|
||||||
|
def.builder.addSuperinterface(inter.tname());
|
||||||
|
|
||||||
|
//generate getter/setter for each method
|
||||||
|
for(Smethod method : inter.methods()){
|
||||||
|
if(method.name().length() <= 3) continue;
|
||||||
|
|
||||||
|
String var = Strings.camelize(method.name().substring(3));
|
||||||
|
//make sure it's a real variable
|
||||||
|
if(!Array.with(def.builder.fieldSpecs).contains(f -> f.name.equals(var))) continue;
|
||||||
|
|
||||||
|
if(method.name().startsWith("get")){
|
||||||
|
def.builder.addMethod(MethodSpec.overriding(method.e).addStatement("return " + var).build());
|
||||||
|
}else if(method.name().startsWith("set")){
|
||||||
|
def.builder.addMethod(MethodSpec.overriding(method.e).addStatement("this." + var + " = " + var).build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write(def.builder, imports.asArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<String> getImports(Element elem){
|
||||||
|
return Array.with(trees.getPath(elem).getCompilationUnit().getImports()).map(Object::toString);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return interface for a component type */
|
||||||
|
String interfaceName(Stype comp){
|
||||||
|
String suffix = "Comp";
|
||||||
|
if(!comp.name().endsWith(suffix)){
|
||||||
|
err("All components must have names that end with 'Comp'.", comp.e);
|
||||||
|
}
|
||||||
|
return comp.name().substring(0, comp.name().length() - suffix.length()) + "c";
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return all components that a entity def has */
|
||||||
|
Array<Stype> allComponents(Stype type){
|
||||||
|
if(!defComponents.containsKey(type)){
|
||||||
|
//get base defs
|
||||||
|
Array<Stype> components = Array.with(mirrors(type)).map(Stype::of);
|
||||||
|
ObjectSet<Stype> out = new ObjectSet<>();
|
||||||
|
for(Stype comp : components){
|
||||||
|
//get dependencies for each def, add them
|
||||||
|
out.add(comp);
|
||||||
|
out.addAll(getDependencies(comp));
|
||||||
|
}
|
||||||
|
|
||||||
|
defComponents.put(type, out.asArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
return defComponents.get(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
Array<Stype> getDependencies(Stype component){
|
||||||
|
if(!componentDependencies.containsKey(component)){
|
||||||
|
ObjectSet<Stype> out = new ObjectSet<>();
|
||||||
|
out.addAll(component.superclasses());
|
||||||
|
|
||||||
|
//get dependency classes
|
||||||
|
if(component.annotation(Depends.class) != null){
|
||||||
|
try{
|
||||||
|
component.annotation(Depends.class).value();
|
||||||
|
}catch(MirroredTypesException e){
|
||||||
|
out.addAll(Array.with(e.getTypeMirrors()).map(Stype::of));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//out now contains the base dependencies; finish constructing the tree
|
||||||
|
ObjectSet<Stype> result = new ObjectSet<>();
|
||||||
|
for(Stype type : out){
|
||||||
|
result.add(type);
|
||||||
|
result.addAll(getDependencies(type));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(component.annotation(BaseComponent.class) == null){
|
||||||
|
result.addAll(baseComponents);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDependencies.put(component, result.asArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
return componentDependencies.get(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypeMirror[] mirrors(Stype type){
|
||||||
|
try{
|
||||||
|
type.annotation(EntityDef.class).value();
|
||||||
|
}catch(MirroredTypesException e){
|
||||||
|
return e.getTypeMirrors().toArray(new TypeMirror[0]);
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Missing components: " + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Definition{
|
||||||
|
final TypeSpec.Builder builder;
|
||||||
|
final Stype base;
|
||||||
|
|
||||||
|
public Definition(Builder builder, Stype base){
|
||||||
|
this.builder = builder;
|
||||||
|
this.base = base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -15,7 +15,7 @@ import java.util.*;
|
|||||||
import java.util.zip.*;
|
import java.util.zip.*;
|
||||||
|
|
||||||
@SupportedAnnotationTypes("mindustry.annotations.Annotations.Serialize")
|
@SupportedAnnotationTypes("mindustry.annotations.Annotations.Serialize")
|
||||||
public class SerializeAnnotationProcessor extends BaseProcessor{
|
public class SerializeProcess extends BaseProcessor{
|
||||||
/** Target class name. */
|
/** Target class name. */
|
||||||
private static final String className = "Serialization";
|
private static final String className = "Serialization";
|
||||||
/** Name of the base package to put all the generated classes. */
|
/** Name of the base package to put all the generated classes. */
|
||||||
@@ -28,7 +28,7 @@ public class SerializeAnnotationProcessor extends BaseProcessor{
|
|||||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
||||||
classBuilder.addStaticBlock(CodeBlock.of(new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(data)))).readUTF()));
|
classBuilder.addStaticBlock(CodeBlock.of(new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(data)))).readUTF()));
|
||||||
classBuilder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unchecked\"").build());
|
classBuilder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unchecked\"").build());
|
||||||
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning);
|
classBuilder.addJavadoc(RemoteProcess.autogenWarning);
|
||||||
|
|
||||||
MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||||
|
|
||||||
@@ -20,7 +20,7 @@ import java.util.Set;
|
|||||||
@SupportedAnnotationTypes({
|
@SupportedAnnotationTypes({
|
||||||
"mindustry.annotations.Annotations.Struct"
|
"mindustry.annotations.Annotations.Struct"
|
||||||
})
|
})
|
||||||
public class StructAnnotationProcessor extends BaseProcessor{
|
public class StructProcess extends BaseProcessor{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(RoundEnvironment env) throws Exception{
|
public void process(RoundEnvironment env) throws Exception{
|
||||||
@@ -41,7 +41,7 @@ public class StructAnnotationProcessor extends BaseProcessor{
|
|||||||
|
|
||||||
try{
|
try{
|
||||||
List<VariableElement> variables = ElementFilter.fieldsIn(elem.getEnclosedElements());
|
List<VariableElement> variables = ElementFilter.fieldsIn(elem.getEnclosedElements());
|
||||||
int structSize = variables.stream().mapToInt(StructAnnotationProcessor::varSize).sum();
|
int structSize = variables.stream().mapToInt(StructProcess::varSize).sum();
|
||||||
int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64);
|
int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64);
|
||||||
|
|
||||||
if(variables.size() == 0){
|
if(variables.size() == 0){
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
package mindustry.annotations.remote;
|
|
||||||
|
|
||||||
import com.squareup.javapoet.*;
|
|
||||||
import mindustry.annotations.*;
|
|
||||||
import mindustry.annotations.Annotations.*;
|
|
||||||
import mindustry.annotations.remote.IOFinder.*;
|
|
||||||
|
|
||||||
import javax.annotation.processing.*;
|
|
||||||
import javax.lang.model.element.*;
|
|
||||||
import javax.tools.Diagnostic.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.*;
|
|
||||||
|
|
||||||
|
|
||||||
/** The annotation processor for generating remote method call code. */
|
|
||||||
@SupportedAnnotationTypes({
|
|
||||||
"mindustry.annotations.Annotations.Remote",
|
|
||||||
"mindustry.annotations.Annotations.WriteClass",
|
|
||||||
"mindustry.annotations.Annotations.ReadClass",
|
|
||||||
})
|
|
||||||
public class RemoteMethodAnnotationProcessor extends BaseProcessor{
|
|
||||||
/** Maximum size of each event packet. */
|
|
||||||
public static final int maxPacketSize = 4096;
|
|
||||||
/** Warning on top of each autogenerated file. */
|
|
||||||
public static final String autogenWarning = "Autogenerated file. Do not modify!\n";
|
|
||||||
|
|
||||||
/** Name of class that handles reading and invoking packets on the server. */
|
|
||||||
private static final String readServerName = "RemoteReadServer";
|
|
||||||
/** Name of class that handles reading and invoking packets on the client. */
|
|
||||||
private static final String readClientName = "RemoteReadClient";
|
|
||||||
/** Simple class name of generated class name. */
|
|
||||||
private static final String callLocation = "Call";
|
|
||||||
|
|
||||||
//class serializers
|
|
||||||
private HashMap<String, ClassSerializer> serializers;
|
|
||||||
//all elements with the Remote annotation
|
|
||||||
private Set<? extends Element> elements;
|
|
||||||
//map of all classes to generate by name
|
|
||||||
private HashMap<String, ClassEntry> classMap;
|
|
||||||
//list of all method entries
|
|
||||||
private ArrayList<MethodEntry> methods;
|
|
||||||
//list of all method entries
|
|
||||||
private ArrayList<ClassEntry> classes;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv){
|
|
||||||
if(round > 1) return false; //only process 2 rounds
|
|
||||||
|
|
||||||
round++;
|
|
||||||
|
|
||||||
try{
|
|
||||||
|
|
||||||
//round 1: find all annotations, generate *writers*
|
|
||||||
if(round == 1){
|
|
||||||
//get serializers
|
|
||||||
serializers = new IOFinder().findSerializers(roundEnv);
|
|
||||||
//last method ID used
|
|
||||||
int lastMethodID = 0;
|
|
||||||
//find all elements with the Remote annotation
|
|
||||||
elements = roundEnv.getElementsAnnotatedWith(Remote.class);
|
|
||||||
//map of all classes to generate by name
|
|
||||||
classMap = new HashMap<>();
|
|
||||||
//list of all method entries
|
|
||||||
methods = new ArrayList<>();
|
|
||||||
//list of all method entries
|
|
||||||
classes = new ArrayList<>();
|
|
||||||
|
|
||||||
List<Element> orderedElements = new ArrayList<>(elements);
|
|
||||||
orderedElements.sort(Comparator.comparing(Object::toString));
|
|
||||||
|
|
||||||
//create methods
|
|
||||||
for(Element element : orderedElements){
|
|
||||||
Remote annotation = element.getAnnotation(Remote.class);
|
|
||||||
|
|
||||||
//check for static
|
|
||||||
if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){
|
|
||||||
BaseProcessor.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element);
|
|
||||||
}
|
|
||||||
|
|
||||||
//can't generate none methods
|
|
||||||
if(annotation.targets() == Loc.none){
|
|
||||||
BaseProcessor.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element);
|
|
||||||
}
|
|
||||||
|
|
||||||
//get and create class entry if needed
|
|
||||||
if(!classMap.containsKey(callLocation)){
|
|
||||||
ClassEntry clas = new ClassEntry(callLocation);
|
|
||||||
classMap.put(callLocation, clas);
|
|
||||||
classes.add(clas);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassEntry entry = classMap.get(callLocation);
|
|
||||||
|
|
||||||
//create and add entry
|
|
||||||
MethodEntry method = new MethodEntry(entry.name, BaseProcessor.getMethodName(element), annotation.targets(), annotation.variants(),
|
|
||||||
annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority());
|
|
||||||
|
|
||||||
entry.methods.add(method);
|
|
||||||
methods.add(method);
|
|
||||||
}
|
|
||||||
|
|
||||||
//create read/write generators
|
|
||||||
RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers);
|
|
||||||
|
|
||||||
//generate the methods to invoke (write)
|
|
||||||
writegen.generateFor(classes, packageName);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}else if(round == 2){ //round 2: generate all *readers*
|
|
||||||
RemoteReadGenerator readgen = new RemoteReadGenerator(serializers);
|
|
||||||
|
|
||||||
//generate server readers
|
|
||||||
readgen.generateFor(methods.stream().filter(method -> method.where.isClient).collect(Collectors.toList()), readServerName, packageName, true);
|
|
||||||
//generate client readers
|
|
||||||
readgen.generateFor(methods.stream().filter(method -> method.where.isServer).collect(Collectors.toList()), readClientName, packageName, false);
|
|
||||||
|
|
||||||
//create class for storing unique method hash
|
|
||||||
TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC);
|
|
||||||
hashBuilder.addJavadoc(autogenWarning);
|
|
||||||
hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL)
|
|
||||||
.initializer("$1L", Objects.hash(methods)).build());
|
|
||||||
|
|
||||||
//build and write resulting hash class
|
|
||||||
TypeSpec spec = hashBuilder.build();
|
|
||||||
JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}catch(Exception e){
|
|
||||||
e.printStackTrace();
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
package mindustry.annotations.remote;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.annotations.remote.IOFinder.*;
|
||||||
|
|
||||||
|
import javax.annotation.processing.*;
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.tools.Diagnostic.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.*;
|
||||||
|
|
||||||
|
|
||||||
|
/** The annotation processor for generating remote method call code. */
|
||||||
|
@SupportedAnnotationTypes({
|
||||||
|
"mindustry.annotations.Annotations.Remote",
|
||||||
|
"mindustry.annotations.Annotations.WriteClass",
|
||||||
|
"mindustry.annotations.Annotations.ReadClass",
|
||||||
|
})
|
||||||
|
public class RemoteProcess extends BaseProcessor{
|
||||||
|
/** Maximum size of each event packet. */
|
||||||
|
public static final int maxPacketSize = 4096;
|
||||||
|
/** Warning on top of each autogenerated file. */
|
||||||
|
public static final String autogenWarning = "Autogenerated file. Do not modify!\n";
|
||||||
|
|
||||||
|
/** Name of class that handles reading and invoking packets on the server. */
|
||||||
|
private static final String readServerName = "RemoteReadServer";
|
||||||
|
/** Name of class that handles reading and invoking packets on the client. */
|
||||||
|
private static final String readClientName = "RemoteReadClient";
|
||||||
|
/** Simple class name of generated class name. */
|
||||||
|
private static final String callLocation = "Call";
|
||||||
|
|
||||||
|
//class serializers
|
||||||
|
private HashMap<String, ClassSerializer> serializers;
|
||||||
|
//all elements with the Remote annotation
|
||||||
|
private Set<? extends Element> elements;
|
||||||
|
//map of all classes to generate by name
|
||||||
|
private HashMap<String, ClassEntry> classMap;
|
||||||
|
//list of all method entries
|
||||||
|
private ArrayList<MethodEntry> methods;
|
||||||
|
//list of all method entries
|
||||||
|
private ArrayList<ClassEntry> classes;
|
||||||
|
|
||||||
|
{
|
||||||
|
rounds = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void process(RoundEnvironment roundEnv) throws Exception{
|
||||||
|
//round 1: find all annotations, generate *writers*
|
||||||
|
if(round == 1){
|
||||||
|
//get serializers
|
||||||
|
serializers = new IOFinder().findSerializers(roundEnv);
|
||||||
|
//last method ID used
|
||||||
|
int lastMethodID = 0;
|
||||||
|
//find all elements with the Remote annotation
|
||||||
|
elements = roundEnv.getElementsAnnotatedWith(Remote.class);
|
||||||
|
//map of all classes to generate by name
|
||||||
|
classMap = new HashMap<>();
|
||||||
|
//list of all method entries
|
||||||
|
methods = new ArrayList<>();
|
||||||
|
//list of all method entries
|
||||||
|
classes = new ArrayList<>();
|
||||||
|
|
||||||
|
List<Element> orderedElements = new ArrayList<>(elements);
|
||||||
|
orderedElements.sort(Comparator.comparing(Object::toString));
|
||||||
|
|
||||||
|
//create methods
|
||||||
|
for(Element element : orderedElements){
|
||||||
|
Remote annotation = element.getAnnotation(Remote.class);
|
||||||
|
|
||||||
|
//check for static
|
||||||
|
if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){
|
||||||
|
BaseProcessor.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element);
|
||||||
|
}
|
||||||
|
|
||||||
|
//can't generate none methods
|
||||||
|
if(annotation.targets() == Loc.none){
|
||||||
|
BaseProcessor.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element);
|
||||||
|
}
|
||||||
|
|
||||||
|
//get and create class entry if needed
|
||||||
|
if(!classMap.containsKey(callLocation)){
|
||||||
|
ClassEntry clas = new ClassEntry(callLocation);
|
||||||
|
classMap.put(callLocation, clas);
|
||||||
|
classes.add(clas);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClassEntry entry = classMap.get(callLocation);
|
||||||
|
|
||||||
|
//create and add entry
|
||||||
|
MethodEntry method = new MethodEntry(entry.name, BaseProcessor.getMethodName(element), annotation.targets(), annotation.variants(),
|
||||||
|
annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority());
|
||||||
|
|
||||||
|
entry.methods.add(method);
|
||||||
|
methods.add(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
//create read/write generators
|
||||||
|
RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers);
|
||||||
|
|
||||||
|
//generate the methods to invoke (write)
|
||||||
|
writegen.generateFor(classes, packageName);
|
||||||
|
}else if(round == 2){ //round 2: generate all *readers*
|
||||||
|
RemoteReadGenerator readgen = new RemoteReadGenerator(serializers);
|
||||||
|
|
||||||
|
//generate server readers
|
||||||
|
readgen.generateFor(methods.stream().filter(method -> method.where.isClient).collect(Collectors.toList()), readServerName, packageName, true);
|
||||||
|
//generate client readers
|
||||||
|
readgen.generateFor(methods.stream().filter(method -> method.where.isServer).collect(Collectors.toList()), readClientName, packageName, false);
|
||||||
|
|
||||||
|
//create class for storing unique method hash
|
||||||
|
TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC);
|
||||||
|
hashBuilder.addJavadoc(autogenWarning);
|
||||||
|
hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL)
|
||||||
|
.initializer("$1L", Objects.hash(methods)).build());
|
||||||
|
|
||||||
|
//build and write resulting hash class
|
||||||
|
TypeSpec spec = hashBuilder.build();
|
||||||
|
JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ public class RemoteReadGenerator{
|
|||||||
throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{
|
throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{
|
||||||
|
|
||||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
||||||
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning);
|
classBuilder.addJavadoc(RemoteProcess.autogenWarning);
|
||||||
|
|
||||||
//create main method builder
|
//create main method builder
|
||||||
MethodSpec.Builder readMethod = MethodSpec.methodBuilder("readPacket")
|
MethodSpec.Builder readMethod = MethodSpec.methodBuilder("readPacket")
|
||||||
|
|||||||
@@ -27,11 +27,11 @@ public class RemoteWriteGenerator{
|
|||||||
for(ClassEntry entry : entries){
|
for(ClassEntry entry : entries){
|
||||||
//create builder
|
//create builder
|
||||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(entry.name).addModifiers(Modifier.PUBLIC);
|
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(entry.name).addModifiers(Modifier.PUBLIC);
|
||||||
classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning);
|
classBuilder.addJavadoc(RemoteProcess.autogenWarning);
|
||||||
|
|
||||||
//add temporary write buffer
|
//add temporary write buffer
|
||||||
classBuilder.addField(FieldSpec.builder(ByteBuffer.class, "TEMP_BUFFER", Modifier.STATIC, Modifier.PRIVATE, Modifier.FINAL)
|
classBuilder.addField(FieldSpec.builder(ByteBuffer.class, "TEMP_BUFFER", Modifier.STATIC, Modifier.PRIVATE, Modifier.FINAL)
|
||||||
.initializer("ByteBuffer.allocate($1L)", RemoteMethodAnnotationProcessor.maxPacketSize).build());
|
.initializer("ByteBuffer.allocate($1L)", RemoteProcess.maxPacketSize).build());
|
||||||
|
|
||||||
//go through each method entry in this class
|
//go through each method entry in this class
|
||||||
for(MethodEntry methodEntry : entry.methods){
|
for(MethodEntry methodEntry : entry.methods){
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package mindustry.annotations.util;
|
||||||
|
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.type.*;
|
||||||
|
|
||||||
|
public class Selement<T extends Element>{
|
||||||
|
public final T e;
|
||||||
|
|
||||||
|
public Selement(T e){
|
||||||
|
this.e = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Element up(){
|
||||||
|
return e.getEnclosingElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeMirror mirror(){
|
||||||
|
return e.asType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeName tname(){
|
||||||
|
return TypeName.get(mirror());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassName cname(){
|
||||||
|
return ClassName.get((TypeElement)BaseProcessor.typeu.asElement(mirror()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String name(){
|
||||||
|
return e.getSimpleName().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return e.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode(){
|
||||||
|
return e.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o){
|
||||||
|
return o != null && o.getClass() == getClass() && ((Selement)o).e.equals(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
package mindustry.annotations.util;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import com.squareup.javapoet.*;
|
||||||
|
import com.sun.source.tree.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.type.*;
|
||||||
|
|
||||||
|
public class Smethod extends Selement<ExecutableElement>{
|
||||||
|
|
||||||
|
public Smethod(ExecutableElement executableElement){
|
||||||
|
super(executableElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean is(Modifier mod){
|
||||||
|
return e.getModifiers().contains(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<TypeMirror> thrown(){
|
||||||
|
return Array.with(e.getThrownTypes()).as(TypeMirror.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<TypeName> thrownt(){
|
||||||
|
return Array.with(e.getThrownTypes()).map(TypeName::get);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<TypeParameterElement> typeVariables(){
|
||||||
|
return Array.with(e.getTypeParameters()).as(TypeParameterElement.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Svar> params(){
|
||||||
|
return Array.with(e.getParameters()).map(Svar::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeMirror ret(){
|
||||||
|
return e.getReturnType();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeName retn(){
|
||||||
|
return TypeName.get(ret());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodTree tree(){
|
||||||
|
return BaseProcessor.trees.getTree(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package mindustry.annotations.util;
|
||||||
|
|
||||||
|
import arc.struct.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
import javax.lang.model.type.*;
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
public class Stype extends Selement<TypeElement>{
|
||||||
|
|
||||||
|
public Stype(TypeElement typeElement){
|
||||||
|
super(typeElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Stype of(TypeMirror mirror){
|
||||||
|
return new Stype((TypeElement)BaseProcessor.typeu.asElement(mirror));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Stype> interfaces(){
|
||||||
|
return Array.with(e.getInterfaces()).map(Stype::of);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Stype> superclasses(){
|
||||||
|
Array<Stype> out = new Array<>();
|
||||||
|
Stype sup = superclass();
|
||||||
|
while(!sup.name().equals("Object")){
|
||||||
|
out.add(sup);
|
||||||
|
sup = sup.superclass();
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stype superclass(){
|
||||||
|
return new Stype((TypeElement)BaseProcessor.typeu.asElement(BaseProcessor.typeu.directSupertypes(mirror()).get(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public <A extends Annotation> A annotation(Class<A> annotation){
|
||||||
|
return e.getAnnotation(annotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Svar> fields(){
|
||||||
|
return Array.with(e.getEnclosedElements()).select(e -> e instanceof VariableElement).map(e -> new Svar((VariableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Smethod> methods(){
|
||||||
|
return Array.with(e.getEnclosedElements()).select(e -> e instanceof ExecutableElement
|
||||||
|
&& !e.getSimpleName().toString().contains("<")).map(e -> new Smethod((ExecutableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Smethod> constructors(){
|
||||||
|
return Array.with(e.getEnclosedElements()).select(e -> e instanceof ExecutableElement
|
||||||
|
&& e.getSimpleName().toString().contains("<")).map(e -> new Smethod((ExecutableElement)e));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TypeMirror mirror(){
|
||||||
|
return e.asType();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package mindustry.annotations.util;
|
||||||
|
|
||||||
|
import com.sun.source.tree.*;
|
||||||
|
import mindustry.annotations.*;
|
||||||
|
|
||||||
|
import javax.lang.model.element.*;
|
||||||
|
|
||||||
|
public class Svar extends Selement<VariableElement>{
|
||||||
|
|
||||||
|
public Svar(VariableElement e){
|
||||||
|
super(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean is(Modifier mod){
|
||||||
|
return e.getModifiers().contains(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VariableTree tree(){
|
||||||
|
return (VariableTree)BaseProcessor.trees.getTree(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
@@ -59,6 +59,7 @@ stat.built = Buildings Built:[accent] {0}
|
|||||||
stat.destroyed = Buildings Destroyed:[accent] {0}
|
stat.destroyed = Buildings Destroyed:[accent] {0}
|
||||||
stat.deconstructed = Buildings Deconstructed:[accent] {0}
|
stat.deconstructed = Buildings Deconstructed:[accent] {0}
|
||||||
stat.delivered = Resources Launched:
|
stat.delivered = Resources Launched:
|
||||||
|
stat.playtime = Time Played:[accent] {0}
|
||||||
stat.rank = Final Rank: [accent]{0}
|
stat.rank = Final Rank: [accent]{0}
|
||||||
|
|
||||||
launcheditems = [accent]Launched Items
|
launcheditems = [accent]Launched Items
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ schematic.exportfile = Esporta File
|
|||||||
schematic.importfile = Importa File
|
schematic.importfile = Importa File
|
||||||
schematic.browseworkshop = Naviga nel Workshop
|
schematic.browseworkshop = Naviga nel Workshop
|
||||||
schematic.copy = Copia negli Appunti
|
schematic.copy = Copia negli Appunti
|
||||||
schematic.copy.import = Incolla dagli Appunti
|
schematic.copy.import = Importa dagli Appunti
|
||||||
schematic.shareworkshop = Condividi nel Workshop
|
schematic.shareworkshop = Condividi nel Workshop
|
||||||
schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Ruota Schematica
|
schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Ruota Schematica
|
||||||
schematic.saved = Schematica salvata.
|
schematic.saved = Schematica salvata.
|
||||||
@@ -59,6 +59,7 @@ stat.built = Costruzioni Erette:[accent] {0}
|
|||||||
stat.destroyed = Costruzioni Distrutte:[accent] {0}
|
stat.destroyed = Costruzioni Distrutte:[accent] {0}
|
||||||
stat.deconstructed = Costruzioni Smantellate:[accent] {0}
|
stat.deconstructed = Costruzioni Smantellate:[accent] {0}
|
||||||
stat.delivered = Risorse Lanciate:
|
stat.delivered = Risorse Lanciate:
|
||||||
|
stat.playtime = Tempo Di Gioco:[accent] {0}
|
||||||
stat.rank = Livello Finale: [accent]{0}
|
stat.rank = Livello Finale: [accent]{0}
|
||||||
|
|
||||||
launcheditems = [accent]Oggetti Lanciati
|
launcheditems = [accent]Oggetti Lanciati
|
||||||
@@ -69,7 +70,7 @@ level.select = Selezione del Livello
|
|||||||
level.mode = Modalità di Gioco:
|
level.mode = Modalità di Gioco:
|
||||||
showagain = Non mostrare più
|
showagain = Non mostrare più
|
||||||
coreattack = < Il Nucleo è sotto attacco! >
|
coreattack = < Il Nucleo è sotto attacco! >
|
||||||
nearpoint = [[ [scarlet]LASCIA LA ZONA NEMICA IMMEDIATAMENTE[] ]\autodistruzione imminente
|
nearpoint = [[ [scarlet]LASCIA LA ZONA NEMICA IMMEDIATAMENTE[] ]\nautodistruzione imminente
|
||||||
database = Database Nucleo
|
database = Database Nucleo
|
||||||
savegame = Salva
|
savegame = Salva
|
||||||
loadgame = Carica
|
loadgame = Carica
|
||||||
@@ -104,6 +105,7 @@ mods.none = [lightgray]Nessuna mod trovata!
|
|||||||
mods.guide = Guida per il modding
|
mods.guide = Guida per il modding
|
||||||
mods.report = Segnala un Bug
|
mods.report = Segnala un Bug
|
||||||
mods.openfolder = Apri Cartella Mods
|
mods.openfolder = Apri Cartella Mods
|
||||||
|
mod.display = [gray]Mod:[orange] {0}
|
||||||
mod.enabled = [lightgray]Abilitato
|
mod.enabled = [lightgray]Abilitato
|
||||||
mod.disabled = [scarlet]Disabilitato
|
mod.disabled = [scarlet]Disabilitato
|
||||||
mod.disable = Disabilita
|
mod.disable = Disabilita
|
||||||
@@ -143,7 +145,7 @@ server.closing = [accent]Chiusura server...
|
|||||||
server.kicked.kick = Sei stato espulso dal server!
|
server.kicked.kick = Sei stato espulso dal server!
|
||||||
server.kicked.whitelist = Non sei presente nella whitelist.
|
server.kicked.whitelist = Non sei presente nella whitelist.
|
||||||
server.kicked.serverClose = Server chiuso.
|
server.kicked.serverClose = Server chiuso.
|
||||||
server.kicked.vote = Sei stato esplso su richiesta dei giocatori. Tanti saluti.
|
server.kicked.vote = Sei stato espulso su richiesta dei giocatori. Tanti saluti.
|
||||||
server.kicked.clientOutdated = Versione del client obsoleta! Aggiorna il gioco!
|
server.kicked.clientOutdated = Versione del client obsoleta! Aggiorna il gioco!
|
||||||
server.kicked.serverOutdated = Server obsoleto! Chiedi all'host di aggiornare la versione del server!
|
server.kicked.serverOutdated = Server obsoleto! Chiedi all'host di aggiornare la versione del server!
|
||||||
server.kicked.banned = Sei stato bandito da questo server.
|
server.kicked.banned = Sei stato bandito da questo server.
|
||||||
@@ -668,6 +670,7 @@ setting.mutesound.name = Silenzia Suoni
|
|||||||
setting.crashreport.name = Invia rapporti anonimi sugli arresti anomali
|
setting.crashreport.name = Invia rapporti anonimi sugli arresti anomali
|
||||||
setting.savecreate.name = Salvataggio Automatico
|
setting.savecreate.name = Salvataggio Automatico
|
||||||
setting.publichost.name = Gioco Visibile Pubblicamente
|
setting.publichost.name = Gioco Visibile Pubblicamente
|
||||||
|
setting.playerlimit.name = Limite Giocatori
|
||||||
setting.chatopacity.name = Opacità Chat
|
setting.chatopacity.name = Opacità Chat
|
||||||
setting.lasersopacity.name = Opacità Raggi Energetici
|
setting.lasersopacity.name = Opacità Raggi Energetici
|
||||||
setting.bridgeopacity.name = Opacità Nastri e Condotti Sopraelevati
|
setting.bridgeopacity.name = Opacità Nastri e Condotti Sopraelevati
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ schematic = Blauwdruk
|
|||||||
schematic.add = Bewaar blauwdruk...
|
schematic.add = Bewaar blauwdruk...
|
||||||
schematics = Blauwdrukken
|
schematics = Blauwdrukken
|
||||||
schematic.replace = Er bestaat al een blauwdruk met die naam. Overschrijven?
|
schematic.replace = Er bestaat al een blauwdruk met die naam. Overschrijven?
|
||||||
schematic.import = Importeer blauwdrul...
|
schematic.import = Importeer blauwdruk...
|
||||||
schematic.exportfile = Exporteer bestand
|
schematic.exportfile = Exporteer bestand
|
||||||
schematic.importfile = Importeer bestand
|
schematic.importfile = Importeer bestand
|
||||||
schematic.browseworkshop = Blader Werkplaats
|
schematic.browseworkshop = Blader Werkplaats
|
||||||
@@ -245,13 +245,13 @@ workshop.listing = Bewerk Workshop vermelding
|
|||||||
ok = Oke
|
ok = Oke
|
||||||
open = Open
|
open = Open
|
||||||
customize = Aanpassen
|
customize = Aanpassen
|
||||||
cancel = Anuleer
|
cancel = Annuleer
|
||||||
openlink = Open Link
|
openlink = Open Link
|
||||||
copylink = Customize Link
|
copylink = Customize Link
|
||||||
back = Teru
|
back = Terug
|
||||||
data.export = Exporteer Data
|
data.export = Exporteer Data
|
||||||
data.import = Importeer Data
|
data.import = Importeer Data
|
||||||
data.exported = Data Geexporteerd.
|
data.exported = Data Geëxporteerd.
|
||||||
data.invalid = Dit is geen geldige game data.
|
data.invalid = Dit is geen geldige game data.
|
||||||
data.import.confirm = Importeren van data verwijderd[scarlet] alle[] huidige data.\n[accent]Dit kan niet ongedaan worden gemaakt![]\n\nWanneer de data is geimport herstart deze game automatisch.
|
data.import.confirm = Importeren van data verwijderd[scarlet] alle[] huidige data.\n[accent]Dit kan niet ongedaan worden gemaakt![]\n\nWanneer de data is geimport herstart deze game automatisch.
|
||||||
classic.export = Exporteer klassieke data
|
classic.export = Exporteer klassieke data
|
||||||
@@ -450,7 +450,7 @@ launch.title = Lancering Sucessvol
|
|||||||
launch.next = [LIGHT_GRAY]volgende lanceerkans in ronde {0}
|
launch.next = [LIGHT_GRAY]volgende lanceerkans in ronde {0}
|
||||||
launch.unable2 = [scarlet]Lanceren niet mogelijk.[]
|
launch.unable2 = [scarlet]Lanceren niet mogelijk.[]
|
||||||
launch.confirm = Dit lanceert alle items in je core.\nJe zal niet meer terug kunnen keren naar deze basis.
|
launch.confirm = Dit lanceert alle items in je core.\nJe zal niet meer terug kunnen keren naar deze basis.
|
||||||
launch.skip.confirm = Als je nu niet lanceert, zul je moeten wachten tot het wel weer kan.
|
launch.skip.confirm = Als je nu niet lanceert zul je moeten wachten tot de volgende mogelijkheid.
|
||||||
uncover = Ontdek
|
uncover = Ontdek
|
||||||
configure = Configureer startinventaris
|
configure = Configureer startinventaris
|
||||||
bannedblocks = Verboden Blokken
|
bannedblocks = Verboden Blokken
|
||||||
@@ -532,21 +532,21 @@ blocks.input = Input
|
|||||||
blocks.output = Output
|
blocks.output = Output
|
||||||
blocks.booster = Booster
|
blocks.booster = Booster
|
||||||
block.unknown = [LIGHT_GRAY]???
|
block.unknown = [LIGHT_GRAY]???
|
||||||
blocks.powercapacity = Stroom Capaciteit
|
blocks.powercapacity = Stroomcapaciteit
|
||||||
blocks.powershot = Stroom/Shot
|
blocks.powershot = Stroom/Schot
|
||||||
blocks.damage = Damage
|
blocks.damage = Schade
|
||||||
blocks.targetsair = Luchtdoelwitten
|
blocks.targetsair = Luchtdoelwitten
|
||||||
blocks.targetsground = Gronddoelwitten
|
blocks.targetsground = Gronddoelwitten
|
||||||
blocks.itemsmoved = Beweegsnelheid
|
blocks.itemsmoved = Beweegsnelheid
|
||||||
blocks.launchtime = Tijd tussen lanceringen
|
blocks.launchtime = Tijd tussen lanceringen
|
||||||
blocks.shootrange = Bereik
|
blocks.shootrange = Bereik
|
||||||
blocks.size = Formaat
|
blocks.size = Formaat
|
||||||
blocks.liquidcapacity = Vloeistof Capaciteit
|
blocks.liquidcapacity = Vloeistofcapaciteit
|
||||||
blocks.powerrange = Stroom Bereik
|
blocks.powerrange = Stroombereik
|
||||||
blocks.powerconnections = Maximale Hoeveelheid Dradem
|
blocks.powerconnections = Maximale Hoeveelheid Connecties
|
||||||
blocks.poweruse = Stroomverbruik
|
blocks.poweruse = Stroomverbruik
|
||||||
blocks.powerdamage = Stroom/Damage
|
blocks.powerdamage = Stroom/Schade
|
||||||
blocks.itemcapacity = Materiaal Capaciteit
|
blocks.itemcapacity = Materiaalcapaciteit
|
||||||
blocks.basepowergeneration = Standaard Stroom Generatie
|
blocks.basepowergeneration = Standaard Stroom Generatie
|
||||||
blocks.productiontime = Productie Tijd
|
blocks.productiontime = Productie Tijd
|
||||||
blocks.repairtime = Volledige Blok Repareertijd
|
blocks.repairtime = Volledige Blok Repareertijd
|
||||||
@@ -556,17 +556,17 @@ blocks.drilltier = Valt te delven
|
|||||||
blocks.drillspeed = Standaard mine snelheid
|
blocks.drillspeed = Standaard mine snelheid
|
||||||
blocks.boosteffect = Boost Effect
|
blocks.boosteffect = Boost Effect
|
||||||
blocks.maxunits = Maximaal Actieve Units
|
blocks.maxunits = Maximaal Actieve Units
|
||||||
blocks.health = Health
|
blocks.health = Levenspunten
|
||||||
blocks.buildtime = Bouwtijd
|
blocks.buildtime = Bouwtijd
|
||||||
blocks.buildcost = Bouwkosten
|
blocks.buildcost = Bouwkosten
|
||||||
blocks.inaccuracy = Onnauwkeurigheid
|
blocks.inaccuracy = Onnauwkeurigheid
|
||||||
blocks.shots = Shoten
|
blocks.shots = Shoten
|
||||||
blocks.reload = Schoten/Seconde
|
blocks.reload = Schoten/Seconde
|
||||||
blocks.ammo = Ammonutie
|
blocks.ammo = Ammunitie
|
||||||
|
|
||||||
bar.drilltierreq = Betere miner nodig
|
bar.drilltierreq = Betere miner nodig
|
||||||
bar.drillspeed = Mining Snelheid: {0}/s
|
bar.drillspeed = Mining Snelheid: {0}/s
|
||||||
bar.pumpspeed = Pomp Snelheid: {0}/s
|
bar.pumpspeed = Pompsnelheid: {0}/s
|
||||||
bar.efficiency = Rendement: {0}%
|
bar.efficiency = Rendement: {0}%
|
||||||
bar.powerbalance = Stroom: {0}
|
bar.powerbalance = Stroom: {0}
|
||||||
bar.powerstored = Opgeslagen: {0}/{1}
|
bar.powerstored = Opgeslagen: {0}/{1}
|
||||||
@@ -591,7 +591,7 @@ bullet.frag = [stat]clusterbom
|
|||||||
bullet.knockback = [stat]{0}[lightgray] terugslag
|
bullet.knockback = [stat]{0}[lightgray] terugslag
|
||||||
bullet.freezing = [stat]bevriezend
|
bullet.freezing = [stat]bevriezend
|
||||||
bullet.tarred = [stat]pek
|
bullet.tarred = [stat]pek
|
||||||
bullet.multiplier = [stat]{0}[lightgray]x ammonutie verdubbelaar
|
bullet.multiplier = [stat]{0}[lightgray]x ammunitieverdubbelaar
|
||||||
bullet.reload = [stat]{0}[lightgray]x herlaad
|
bullet.reload = [stat]{0}[lightgray]x herlaad
|
||||||
|
|
||||||
unit.blocks = blokken
|
unit.blocks = blokken
|
||||||
@@ -615,8 +615,8 @@ category.items = Items
|
|||||||
category.crafting = Productie
|
category.crafting = Productie
|
||||||
category.shooting = Wapens
|
category.shooting = Wapens
|
||||||
category.optional = Optionele Verbeteringen
|
category.optional = Optionele Verbeteringen
|
||||||
setting.landscape.name = Vergrendel Landscape
|
setting.landscape.name = Vergrendel Landschap
|
||||||
setting.shadows.name = Schaduws
|
setting.shadows.name = Schaduwen
|
||||||
setting.blockreplace.name = Automatische Blok Suggesties
|
setting.blockreplace.name = Automatische Blok Suggesties
|
||||||
setting.linear.name = Linear Filtering
|
setting.linear.name = Linear Filtering
|
||||||
setting.hints.name = Hints
|
setting.hints.name = Hints
|
||||||
@@ -629,14 +629,14 @@ setting.autotarget.name = Auto-Target
|
|||||||
setting.keyboard.name = Muis+Toetsenbord Controls
|
setting.keyboard.name = Muis+Toetsenbord Controls
|
||||||
setting.touchscreen.name = Touchscreen Controls
|
setting.touchscreen.name = Touchscreen Controls
|
||||||
setting.fpscap.name = Max FPS
|
setting.fpscap.name = Max FPS
|
||||||
setting.fpscap.none = None
|
setting.fpscap.none = Geen
|
||||||
setting.fpscap.text = {0} FPS
|
setting.fpscap.text = {0} FPS
|
||||||
setting.uiscale.name = UI Schaal[lightgray] (herstart vereist)[]
|
setting.uiscale.name = UI Schaal[lightgray] (herstart vereist)[]
|
||||||
setting.swapdiagonal.name = Altijd Diagonaal Plaatsen
|
setting.swapdiagonal.name = Altijd Diagonaal Plaatsen
|
||||||
setting.difficulty.training = kalm
|
setting.difficulty.training = oefening
|
||||||
setting.difficulty.easy = makkelijk
|
setting.difficulty.easy = makkelijk
|
||||||
setting.difficulty.normal = normaal
|
setting.difficulty.normal = normaal
|
||||||
setting.difficulty.hard = hard
|
setting.difficulty.hard = moeilijk
|
||||||
setting.difficulty.insane = krankzinnig
|
setting.difficulty.insane = krankzinnig
|
||||||
setting.difficulty.name = Moeilijkheidsgraad:
|
setting.difficulty.name = Moeilijkheidsgraad:
|
||||||
setting.screenshake.name = Schuddend Scherm
|
setting.screenshake.name = Schuddend Scherm
|
||||||
@@ -932,7 +932,7 @@ block.lancer.name = Lancer
|
|||||||
block.conveyor.name = Lopende Band
|
block.conveyor.name = Lopende Band
|
||||||
block.titanium-conveyor.name = Titanium Lopende Band
|
block.titanium-conveyor.name = Titanium Lopende Band
|
||||||
block.armored-conveyor.name = Gepantserde Lopende Band
|
block.armored-conveyor.name = Gepantserde Lopende Band
|
||||||
block.armored-conveyor.description = Verplaatst items met dezelfde snelheid als een van titanium, maar heeft meer levenspunten. accepteert alleen items van de zijkanten als het ook lopende banden zijn.
|
block.armored-conveyor.description = Verplaatst items met dezelfde snelheid als een van titanium, maar heeft meer levenspunten. Accepteert alleen items van de zijkanten als het ook lopende banden zijn.
|
||||||
block.junction.name = Kruising
|
block.junction.name = Kruising
|
||||||
block.router.name = Router
|
block.router.name = Router
|
||||||
block.distributor.name = Distributor
|
block.distributor.name = Distributor
|
||||||
@@ -1060,7 +1060,7 @@ unit.eradicator.name = Eradicator
|
|||||||
unit.lich.name = Lich
|
unit.lich.name = Lich
|
||||||
unit.reaper.name = Reaper
|
unit.reaper.name = Reaper
|
||||||
tutorial.next = [lightgray]<Klik om verder te gaan>
|
tutorial.next = [lightgray]<Klik om verder te gaan>
|
||||||
tutorial.intro = Welkom bij de[scarlet] Mindustry Tutorial.[]\nBegin met het[accent] delven van koper[]. Klik op een vakje die het heeft om het te delven.\n\n[accent]{0}/{1} koper
|
tutorial.intro = Welkom bij de[scarlet] Mindustry Tutorial.[]\nBegin met het[accent] delven van koper[]. Klik op een vakje met koper om het te delven.\n\n[accent]{0}/{1} koper
|
||||||
tutorial.intro.mobile = Welkom bij de[scarlet] Mindustry Tutorial.[]\nVeeg over het scherm om te bewegen.\n[accent]Knijp met 2 vingers [] om in en uit te zoomen.\nBegin met het[accent] delven van koper[]. Beweeg dichterbij, en klik er dan op.\n\n[accent]{0}/{1} koper
|
tutorial.intro.mobile = Welkom bij de[scarlet] Mindustry Tutorial.[]\nVeeg over het scherm om te bewegen.\n[accent]Knijp met 2 vingers [] om in en uit te zoomen.\nBegin met het[accent] delven van koper[]. Beweeg dichterbij, en klik er dan op.\n\n[accent]{0}/{1} koper
|
||||||
tutorial.drill = Met de hand delven is inefficient.\n[accent]Drills []kunnen automatisch voor je delven.\nPlaats er een op de koper.
|
tutorial.drill = Met de hand delven is inefficient.\n[accent]Drills []kunnen automatisch voor je delven.\nPlaats er een op de koper.
|
||||||
tutorial.drill.mobile = Met de hand delven is inefficient.\n[accent]Drills []kunnen automatisch voor je delven.\nZoek de drill rechts onderin.\nSelecter de[accent] mechanische drill[].\nPlaats het op de koper door erop te klikken, druk dan op het[accent] vinkje[] om het bouwen te bevestigen.\nKlik op de[accent] X knop[] om het te anuleren.
|
tutorial.drill.mobile = Met de hand delven is inefficient.\n[accent]Drills []kunnen automatisch voor je delven.\nZoek de drill rechts onderin.\nSelecter de[accent] mechanische drill[].\nPlaats het op de koper door erop te klikken, druk dan op het[accent] vinkje[] om het bouwen te bevestigen.\nKlik op de[accent] X knop[] om het te anuleren.
|
||||||
@@ -1068,8 +1068,8 @@ tutorial.blockinfo = Elk blok heeft andere statistieken. Elke drill kan enkel be
|
|||||||
tutorial.conveyor = [accent]Lopende Banden[] worden gebruikt om je items naar je core te krijgen.\nLeg een line aan van je drills tot aan je core.
|
tutorial.conveyor = [accent]Lopende Banden[] worden gebruikt om je items naar je core te krijgen.\nLeg een line aan van je drills tot aan je core.
|
||||||
tutorial.conveyor.mobile = [accent]Lopende Banden[] worden gebruikt om je items naar je core te krijgen.\nLeg een line aan van je drills tot aan je core.\n[accent] Doe dit door je vinger een paar seconden stil te houden[] en dan in een richting te slepen.\n\n[accent]{0}/{1} lopende banden in 1x geplaatst\n[accent]0/1 items afgeleverd
|
tutorial.conveyor.mobile = [accent]Lopende Banden[] worden gebruikt om je items naar je core te krijgen.\nLeg een line aan van je drills tot aan je core.\n[accent] Doe dit door je vinger een paar seconden stil te houden[] en dan in een richting te slepen.\n\n[accent]{0}/{1} lopende banden in 1x geplaatst\n[accent]0/1 items afgeleverd
|
||||||
tutorial.turret = Defensieve gebouwen moeten worden gebouwd tegen de[LIGHT_GRAY] vijand[].\nBouw een duo kannon bij je basis.
|
tutorial.turret = Defensieve gebouwen moeten worden gebouwd tegen de[LIGHT_GRAY] vijand[].\nBouw een duo kannon bij je basis.
|
||||||
tutorial.drillturret = Duo's hebben[accent] koperen ammonutie []nodig om te schieten.\nPlaatst een drill ernaast om het van koper te voorzien.
|
tutorial.drillturret = Duo's hebben[accent] koperen ammunitie []nodig om te schieten.\nPlaats een drill ernaast om het van koper te voorzien.
|
||||||
tutorial.pause = Tijdens een gevecht is het mogelijk[accent] het spel te pauzeren.[]\nJe kan nog wel je gebouwen plannen dan.\n\n[accent]Pauzeer het spel (spatie) nu.
|
tutorial.pause = Tijdens een gevecht is het mogelijk[accent] het spel te pauzeren.[]\nJe kan nog wel je gebouwen plannen.\n\n[accent]Pauzeer het spel (spatie) nu.
|
||||||
tutorial.pause.mobile = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press this button in the top left to pause.
|
tutorial.pause.mobile = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press this button in the top left to pause.
|
||||||
tutorial.unpause = Doe het opnieuw om weer verder te gaan.
|
tutorial.unpause = Doe het opnieuw om weer verder te gaan.
|
||||||
tutorial.unpause.mobile = Doe het opnieuw om weer verder te gaan.
|
tutorial.unpause.mobile = Doe het opnieuw om weer verder te gaan.
|
||||||
@@ -1079,10 +1079,10 @@ tutorial.withdraw = In sommige situaties, is het nodig om items uit een blok te
|
|||||||
tutorial.deposit = Je kan de items weer terugstoppen door van je schip het terug te slepen naar waar je het wilt.\n\n[accent]Stop het nu weer terug in de core.[]
|
tutorial.deposit = Je kan de items weer terugstoppen door van je schip het terug te slepen naar waar je het wilt.\n\n[accent]Stop het nu weer terug in de core.[]
|
||||||
tutorial.waves = De[LIGHT_GRAY] vijand[] naderd.\n\nVerdedig je core voor 2 rondes. Bouw meer verdedigingen.
|
tutorial.waves = De[LIGHT_GRAY] vijand[] naderd.\n\nVerdedig je core voor 2 rondes. Bouw meer verdedigingen.
|
||||||
tutorial.waves.mobile = De[LIGHT_GRAY] vijand[] naderd.\n\nVerdedig je core voor 2 rondes. Je schip schiet automatisch op vijanden.\nBouw meer verdedigingen, en mine meer koper.
|
tutorial.waves.mobile = De[LIGHT_GRAY] vijand[] naderd.\n\nVerdedig je core voor 2 rondes. Je schip schiet automatisch op vijanden.\nBouw meer verdedigingen, en mine meer koper.
|
||||||
tutorial.launch = Tijdens sommige waves, kan je je core[accent] lanceren[], hiermee verlaat je de basis permanent[accent] maar je neemt wel alles dat in de core zit met je mee.[]\nVervolgens valt ermee te onderzoeken.\n\n[accent]Druk op de lanceer knop.
|
tutorial.launch = Tijdens sommige waves, kan je je core[accent] lanceren[], hiermee verlaat je de basis permanent[accent] maar je neemt wel alles dat in de core zit met je mee.[]\nMet deze grondstoffen kan je nieuwe technologieën onderzoeken.\n\n[accent]Druk op de lanceerknop.
|
||||||
|
|
||||||
item.copper.description = A useful structure material. Used extensively in all types of blocks.
|
item.copper.description = Een nuttig materiaal voor gebouwen. Wordt erg vaak in blokken gebruikt.
|
||||||
item.lead.description = A basic starter material. Used extensively in electronics and liquid transportation blocks.
|
item.lead.description = Een basismateriaal. Wordt vaak gebruikt in elektronica en vloeistoftransport.
|
||||||
item.metaglass.description = A super-tough glass compound. Extensively used for liquid distribution and storage.
|
item.metaglass.description = A super-tough glass compound. Extensively used for liquid distribution and storage.
|
||||||
item.graphite.description = Mineralized carbon, used for ammunition and electrical insulation.
|
item.graphite.description = Mineralized carbon, used for ammunition and electrical insulation.
|
||||||
item.sand.description = A common material that is used extensively in smelting, both in alloying and as a flux.
|
item.sand.description = A common material that is used extensively in smelting, both in alloying and as a flux.
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 763 B After Width: | Height: | Size: 754 B |
|
Before Width: | Height: | Size: 726 KiB After Width: | Height: | Size: 726 KiB |
|
Before Width: | Height: | Size: 894 KiB After Width: | Height: | Size: 894 KiB |
|
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 262 KiB |
@@ -39,7 +39,7 @@ public class WaveSpawner{
|
|||||||
|
|
||||||
/** @return true if the player is near a ground spawn point. */
|
/** @return true if the player is near a ground spawn point. */
|
||||||
public boolean playerNear(){
|
public boolean playerNear(){
|
||||||
return groundSpawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius);
|
return groundSpawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius && player.getTeam() != state.rules.waveTeam);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnEnemies(){
|
public void spawnEnemies(){
|
||||||
|
|||||||
@@ -166,6 +166,13 @@ public class Renderer implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resume(){
|
||||||
|
if(settings.getBool("bloom") && bloom != null){
|
||||||
|
bloom.resume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void setupBloom(){
|
void setupBloom(){
|
||||||
try{
|
try{
|
||||||
if(bloom != null){
|
if(bloom != null){
|
||||||
|
|||||||
@@ -1,15 +1,14 @@
|
|||||||
package mindustry.entities;
|
package mindustry.entities;
|
||||||
|
|
||||||
import arc.Core;
|
import arc.*;
|
||||||
import arc.struct.Array;
|
import arc.func.*;
|
||||||
import arc.func.Cons;
|
import arc.graphics.*;
|
||||||
import arc.graphics.Color;
|
|
||||||
import arc.graphics.g2d.*;
|
import arc.graphics.g2d.*;
|
||||||
import arc.math.Mathf;
|
import arc.math.*;
|
||||||
import arc.math.geom.Position;
|
import arc.math.geom.*;
|
||||||
import arc.util.pooling.Pools;
|
import arc.struct.*;
|
||||||
import mindustry.entities.type.EffectEntity;
|
import arc.util.pooling.*;
|
||||||
import mindustry.entities.traits.ScaleTrait;
|
import mindustry.entities.type.*;
|
||||||
|
|
||||||
public class Effects{
|
public class Effects{
|
||||||
private static final EffectContainer container = new EffectContainer();
|
private static final EffectContainer container = new EffectContainer();
|
||||||
@@ -126,7 +125,7 @@ public class Effects{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class EffectContainer implements ScaleTrait{
|
public static class EffectContainer implements Scaled{
|
||||||
public float x, y, time, lifetime, rotation;
|
public float x, y, time, lifetime, rotation;
|
||||||
public Color color;
|
public Color color;
|
||||||
public int id;
|
public int id;
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ public class EntityGroup<T extends Entity> implements Iterable<T>{
|
|||||||
entitiesToAdd.clear();
|
entitiesToAdd.clear();
|
||||||
|
|
||||||
for(T e : entitiesToRemove){
|
for(T e : entitiesToRemove){
|
||||||
entityArray.removeValue(e, true);
|
entityArray.remove(e, true);
|
||||||
if(map != null){
|
if(map != null){
|
||||||
map.remove(e.getID());
|
map.remove(e.getID());
|
||||||
}
|
}
|
||||||
@@ -148,7 +148,7 @@ public class EntityGroup<T extends Entity> implements Iterable<T>{
|
|||||||
}else{ //maybe it's being queued?
|
}else{ //maybe it's being queued?
|
||||||
for(T check : entitiesToAdd){
|
for(T check : entitiesToAdd){
|
||||||
if(check.getID() == id){ //if it is indeed queued, remove it
|
if(check.getID() == id){ //if it is indeed queued, remove it
|
||||||
entitiesToAdd.removeValue(check, true);
|
entitiesToAdd.remove(check, true);
|
||||||
if(removeListener != null){
|
if(removeListener != null){
|
||||||
removeListener.get(check);
|
removeListener.get(check);
|
||||||
}
|
}
|
||||||
|
|||||||
231
core/src/mindustry/entities/def/EntityComps.java
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
package mindustry.entities.def;
|
||||||
|
|
||||||
|
import arc.graphics.*;
|
||||||
|
import arc.math.*;
|
||||||
|
import arc.math.geom.*;
|
||||||
|
import arc.struct.Bits;
|
||||||
|
import arc.struct.*;
|
||||||
|
import arc.util.*;
|
||||||
|
import arc.util.pooling.*;
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.content.*;
|
||||||
|
import mindustry.ctype.*;
|
||||||
|
import mindustry.entities.bullet.*;
|
||||||
|
import mindustry.entities.units.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
import mindustry.type.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
import static mindustry.Vars.content;
|
||||||
|
|
||||||
|
public class EntityComps{
|
||||||
|
|
||||||
|
@Depends({HealthComp.class, VelComp.class, StatusComp.class})
|
||||||
|
class UnitComp{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class OwnerComp{
|
||||||
|
Entityc owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Depends({TimedComp.class})
|
||||||
|
class BulletComp{
|
||||||
|
BulletType bullet;
|
||||||
|
|
||||||
|
void init(){
|
||||||
|
bullet.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class TimedComp extends EntityComp implements Scaled{
|
||||||
|
float time, lifetime;
|
||||||
|
|
||||||
|
void update(){
|
||||||
|
time = Math.min(time + Time.delta(), lifetime);
|
||||||
|
|
||||||
|
if(time >= lifetime){
|
||||||
|
remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float fin(){
|
||||||
|
return time / lifetime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HealthComp{
|
||||||
|
float health, maxHealth;
|
||||||
|
boolean dead;
|
||||||
|
|
||||||
|
float healthf(){
|
||||||
|
return health / maxHealth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class PosComp implements Position{
|
||||||
|
float x, y;
|
||||||
|
|
||||||
|
void set(float x, float y){
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Depends(PosComp.class)
|
||||||
|
class VelComp{
|
||||||
|
//transient fields act as imports from any other component clases; these are ignored by the generator
|
||||||
|
transient float x, y;
|
||||||
|
|
||||||
|
final Vec2 vel = new Vec2();
|
||||||
|
|
||||||
|
void update(){
|
||||||
|
x += vel.x;
|
||||||
|
y += vel.y;
|
||||||
|
vel.scl(0.9f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Depends(PosComp.class)
|
||||||
|
class HitboxComp{
|
||||||
|
transient float x, y;
|
||||||
|
|
||||||
|
float hitSize;
|
||||||
|
|
||||||
|
boolean collides(Hitboxc other){
|
||||||
|
return Intersector.overlapsRect(x - hitSize/2f, y - hitSize/2f, hitSize, hitSize,
|
||||||
|
other.getX() - other.getHitSize()/2f, other.getY() - other.getHitSize()/2f, other.getHitSize(), other.getHitSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Depends(PosComp.class)
|
||||||
|
class StatusComp{
|
||||||
|
private Array<StatusEntry> statuses = new Array<>();
|
||||||
|
private Bits applied = new Bits(content.getBy(ContentType.status).size);
|
||||||
|
|
||||||
|
private float speedMultiplier;
|
||||||
|
private float damageMultiplier;
|
||||||
|
private float armorMultiplier;
|
||||||
|
|
||||||
|
void apply(StatusEffect effect, float duration){
|
||||||
|
if(effect == StatusEffects.none || effect == null || isImmune(effect)) return; //don't apply empty or immune effects
|
||||||
|
|
||||||
|
if(statuses.size > 0){
|
||||||
|
//check for opposite effects
|
||||||
|
for(StatusEntry entry : statuses){
|
||||||
|
//extend effect
|
||||||
|
if(entry.effect == effect){
|
||||||
|
entry.time = Math.max(entry.time, duration);
|
||||||
|
return;
|
||||||
|
}else if(entry.effect.reactsWith(effect)){ //find opposite
|
||||||
|
StatusEntry.tmp.effect = entry.effect;
|
||||||
|
//TODO unit cannot be null here
|
||||||
|
entry.effect.getTransition(null, effect, entry.time, duration, StatusEntry.tmp);
|
||||||
|
entry.time = StatusEntry.tmp.time;
|
||||||
|
|
||||||
|
if(StatusEntry.tmp.effect != entry.effect){
|
||||||
|
entry.effect = StatusEntry.tmp.effect;
|
||||||
|
}
|
||||||
|
|
||||||
|
//stop looking when one is found
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//otherwise, no opposites found, add direct effect
|
||||||
|
StatusEntry entry = Pools.obtain(StatusEntry.class, StatusEntry::new);
|
||||||
|
entry.set(effect, duration);
|
||||||
|
statuses.add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isImmune(StatusEffect effect){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color getStatusColor(){
|
||||||
|
if(statuses.size == 0){
|
||||||
|
return Tmp.c1.set(Color.white);
|
||||||
|
}
|
||||||
|
|
||||||
|
float r = 0f, g = 0f, b = 0f;
|
||||||
|
for(StatusEntry entry : statuses){
|
||||||
|
r += entry.effect.color.r;
|
||||||
|
g += entry.effect.color.g;
|
||||||
|
b += entry.effect.color.b;
|
||||||
|
}
|
||||||
|
return Tmp.c1.set(r / statuses.size, g / statuses.size, b / statuses.size, 1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(){
|
||||||
|
applied.clear();
|
||||||
|
speedMultiplier = damageMultiplier = armorMultiplier = 1f;
|
||||||
|
|
||||||
|
if(statuses.isEmpty()) return;
|
||||||
|
|
||||||
|
statuses.eachFilter(entry -> {
|
||||||
|
entry.time = Math.max(entry.time - Time.delta(), 0);
|
||||||
|
applied.set(entry.effect.id);
|
||||||
|
|
||||||
|
if(entry.time <= 0){
|
||||||
|
Pools.free(entry);
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
speedMultiplier *= entry.effect.speedMultiplier;
|
||||||
|
armorMultiplier *= entry.effect.armorMultiplier;
|
||||||
|
damageMultiplier *= entry.effect.damageMultiplier;
|
||||||
|
//TODO unit can't be null
|
||||||
|
entry.effect.update(null, entry.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean hasEffect(StatusEffect effect){
|
||||||
|
return applied.get(effect.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSave(DataOutput stream) throws IOException{
|
||||||
|
stream.writeByte(statuses.size);
|
||||||
|
for(StatusEntry entry : statuses){
|
||||||
|
stream.writeByte(entry.effect.id);
|
||||||
|
stream.writeFloat(entry.time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void readSave(DataInput stream, byte version) throws IOException{
|
||||||
|
for(StatusEntry effect : statuses){
|
||||||
|
Pools.free(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
statuses.clear();
|
||||||
|
|
||||||
|
byte amount = stream.readByte();
|
||||||
|
for(int i = 0; i < amount; i++){
|
||||||
|
byte id = stream.readByte();
|
||||||
|
float time = stream.readFloat();
|
||||||
|
StatusEntry entry = Pools.obtain(StatusEntry.class, StatusEntry::new);
|
||||||
|
entry.set(content.getByID(ContentType.status, id), time);
|
||||||
|
statuses.add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@BaseComponent
|
||||||
|
class EntityComp{
|
||||||
|
int id;
|
||||||
|
|
||||||
|
void init(){}
|
||||||
|
|
||||||
|
void update(){}
|
||||||
|
|
||||||
|
void remove(){}
|
||||||
|
|
||||||
|
<T> T as(Class<T> type){
|
||||||
|
return (T)this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
core/src/mindustry/entities/def/EntityDefs.java
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
package mindustry.entities.def;
|
||||||
|
|
||||||
|
import mindustry.annotations.Annotations.*;
|
||||||
|
import mindustry.entities.def.EntityComps.*;
|
||||||
|
|
||||||
|
class EntityDefs{
|
||||||
|
|
||||||
|
@EntityDef({BulletComp.class, VelComp.class, TimedComp.class})
|
||||||
|
class BulletDef{}
|
||||||
|
}
|
||||||
@@ -28,8 +28,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
|||||||
private Position to;
|
private Position to;
|
||||||
private Runnable done;
|
private Runnable done;
|
||||||
|
|
||||||
public ItemTransfer(){
|
public ItemTransfer(){}
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(called = Loc.server, unreliable = true)
|
@Remote(called = Loc.server, unreliable = true)
|
||||||
public static void transferItemEffect(Item item, float x, float y, Unit to){
|
public static void transferItemEffect(Item item, float x, float y, Unit to){
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
package mindustry.entities.traits;
|
|
||||||
|
|
||||||
import arc.math.Interpolation;
|
|
||||||
|
|
||||||
public interface ScaleTrait{
|
|
||||||
/** 0 to 1. */
|
|
||||||
float fin();
|
|
||||||
|
|
||||||
/** 1 to 0 */
|
|
||||||
default float fout(){
|
|
||||||
return 1f - fin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 1 to 0 */
|
|
||||||
default float fout(Interpolation i){
|
|
||||||
return i.apply(fout());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 1 to 0, ending at the specified margin */
|
|
||||||
default float fout(float margin){
|
|
||||||
float f = fin();
|
|
||||||
if(f >= 1f - margin){
|
|
||||||
return 1f - (f - (1f - margin)) / margin;
|
|
||||||
}else{
|
|
||||||
return 1f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 0 to 1 **/
|
|
||||||
default float fin(Interpolation i){
|
|
||||||
return i.apply(fin());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 0 to 1 */
|
|
||||||
default float finpow(){
|
|
||||||
return Interpolation.pow3Out.apply(fin());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 0 to 1 to 0 */
|
|
||||||
default float fslope(){
|
|
||||||
return (0.5f - Math.abs(fin() - 0.5f)) * 2f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
package mindustry.entities.traits;
|
package mindustry.entities.traits;
|
||||||
|
|
||||||
import arc.math.Mathf;
|
import arc.math.*;
|
||||||
import arc.util.Time;
|
import arc.util.Time;
|
||||||
|
|
||||||
public interface TimeTrait extends ScaleTrait, Entity{
|
public interface TimeTrait extends Scaled, Entity{
|
||||||
|
|
||||||
float lifetime();
|
float lifetime();
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import mindustry.world.*;
|
|||||||
|
|
||||||
import static mindustry.Vars.*;
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Poolable, DrawTrait, VelocityTrait, TimeTrait, TeamTrait, AbsorbTrait{
|
public class Bullet extends SolidEntity implements DamageTrait, Scaled, Poolable, DrawTrait, VelocityTrait, TimeTrait, TeamTrait, AbsorbTrait{
|
||||||
public Interval timer = new Interval(3);
|
public Interval timer = new Interval(3);
|
||||||
|
|
||||||
private float lifeScl;
|
private float lifeScl;
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import static mindustry.Vars.*;
|
|||||||
public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||||
public static final int timerSync = 2;
|
public static final int timerSync = 2;
|
||||||
public static final int timerAbility = 3;
|
public static final int timerAbility = 3;
|
||||||
public static final int timerTransfer = 4;
|
|
||||||
private static final int timerShootLeft = 0;
|
private static final int timerShootLeft = 0;
|
||||||
private static final int timerShootRight = 1;
|
private static final int timerShootRight = 1;
|
||||||
private static final float liftoffBoost = 0.2f;
|
private static final float liftoffBoost = 0.2f;
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
other.block().onProximityUpdate(other);
|
other.block().onProximityUpdate(other);
|
||||||
|
|
||||||
if(other.entity != null){
|
if(other.entity != null){
|
||||||
other.entity.proximity.removeValue(tile, true);
|
other.entity.proximity.remove(tile, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
package mindustry.entities.type;
|
package mindustry.entities.type;
|
||||||
|
|
||||||
import arc.util.pooling.Pool.Poolable;
|
import arc.util.pooling.Pool.*;
|
||||||
import mindustry.entities.traits.ScaleTrait;
|
import mindustry.entities.traits.*;
|
||||||
import mindustry.entities.traits.TimeTrait;
|
|
||||||
|
|
||||||
public abstract class TimedEntity extends BaseEntity implements ScaleTrait, TimeTrait, Poolable{
|
public abstract class TimedEntity extends BaseEntity implements TimeTrait, Poolable{
|
||||||
public float time;
|
public float time;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
16
core/src/mindustry/entities/units/StatusEntry.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package mindustry.entities.units;
|
||||||
|
|
||||||
|
import mindustry.type.*;
|
||||||
|
|
||||||
|
public class StatusEntry{
|
||||||
|
public static final StatusEntry tmp = new StatusEntry();
|
||||||
|
|
||||||
|
public StatusEffect effect;
|
||||||
|
public float time;
|
||||||
|
|
||||||
|
public StatusEntry set(StatusEffect effect, float time){
|
||||||
|
this.effect = effect;
|
||||||
|
this.time = time;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -147,14 +147,4 @@ public class Statuses implements Saveable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class StatusEntry{
|
|
||||||
public StatusEffect effect;
|
|
||||||
public float time;
|
|
||||||
|
|
||||||
public StatusEntry set(StatusEffect effect, float time){
|
|
||||||
this.effect = effect;
|
|
||||||
this.time = time;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ public class Saves{
|
|||||||
|
|
||||||
public void delete(){
|
public void delete(){
|
||||||
file.delete();
|
file.delete();
|
||||||
saves.removeValue(this, true);
|
saves.remove(this, true);
|
||||||
if(this == current){
|
if(this == current){
|
||||||
current = null;
|
current = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,382 +0,0 @@
|
|||||||
package mindustry.graphics;
|
|
||||||
|
|
||||||
import arc.Core;
|
|
||||||
import arc.graphics.*;
|
|
||||||
import arc.graphics.Pixmap.Format;
|
|
||||||
import arc.graphics.VertexAttributes.Usage;
|
|
||||||
import arc.graphics.gl.FrameBuffer;
|
|
||||||
import arc.graphics.gl.Shader;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bloomlib allow easy but efficient way to add bloom effect as post process
|
|
||||||
* effect
|
|
||||||
*
|
|
||||||
* @author kalle_h
|
|
||||||
*/
|
|
||||||
public class Bloom{
|
|
||||||
/**
|
|
||||||
* To use implement bloom more like a glow. Texture alpha channel can be
|
|
||||||
* used as mask which part are glowing and which are not. see more info at:
|
|
||||||
* http://www.gamasutra.com/view/feature/2107/realtime_glow.php
|
|
||||||
* <p>
|
|
||||||
* NOTE: need to be set before bloom instance is created. After that this
|
|
||||||
* does nothing.
|
|
||||||
*/
|
|
||||||
public static boolean useAlphaChannelAsMask = false;
|
|
||||||
|
|
||||||
/** how many blur pass */
|
|
||||||
public int blurPasses = 1;
|
|
||||||
|
|
||||||
private Shader tresholdShader;
|
|
||||||
private Shader bloomShader;
|
|
||||||
|
|
||||||
private Mesh fullScreenQuad;
|
|
||||||
|
|
||||||
private Texture pingPongTex1;
|
|
||||||
private Texture pingPongTex2;
|
|
||||||
private Texture original;
|
|
||||||
|
|
||||||
private FrameBuffer frameBuffer;
|
|
||||||
private FrameBuffer pingPongBuffer1;
|
|
||||||
private FrameBuffer pingPongBuffer2;
|
|
||||||
|
|
||||||
private Shader blurShader;
|
|
||||||
|
|
||||||
private float bloomIntensity;
|
|
||||||
private float originalIntensity;
|
|
||||||
private float threshold;
|
|
||||||
private int w;
|
|
||||||
private int h;
|
|
||||||
private boolean blending = false;
|
|
||||||
private boolean capturing = false;
|
|
||||||
private float r = 0f;
|
|
||||||
private float g = 0f;
|
|
||||||
private float b = 0f;
|
|
||||||
private float a = 1f;
|
|
||||||
private boolean disposeFBO = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* IMPORTANT NOTE CALL THIS WHEN RESUMING
|
|
||||||
*/
|
|
||||||
public void resume(){
|
|
||||||
bloomShader.begin();
|
|
||||||
bloomShader.setUniformi("u_texture0", 0);
|
|
||||||
bloomShader.setUniformi("u_texture1", 1);
|
|
||||||
bloomShader.end();
|
|
||||||
|
|
||||||
setSize(w, h);
|
|
||||||
setThreshold(threshold);
|
|
||||||
setBloomIntesity(bloomIntensity);
|
|
||||||
setOriginalIntesity(originalIntensity);
|
|
||||||
|
|
||||||
original = frameBuffer.getTexture();
|
|
||||||
pingPongTex1 = pingPongBuffer1.getTexture();
|
|
||||||
pingPongTex2 = pingPongBuffer2.getTexture();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize bloom class that capsulate original scene capturate,
|
|
||||||
* tresholding, gaussian blurring and blending. Default values: depth = true
|
|
||||||
* blending = false 32bits = true
|
|
||||||
*/
|
|
||||||
public Bloom(){
|
|
||||||
initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4, null, false, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Bloom(boolean useBlending){
|
|
||||||
initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4, null, false, useBlending, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize bloom class that capsulate original scene capturate,
|
|
||||||
* tresholding, gaussian blurring and blending.
|
|
||||||
*
|
|
||||||
* @param FBO_W
|
|
||||||
* @param FBO_H how big fbo is used for bloom texture, smaller = more blur and
|
|
||||||
* lot faster but aliasing can be problem
|
|
||||||
* @param hasDepth do rendering need depth buffer
|
|
||||||
* @param useBlending does fbo need alpha channel and is blending enabled when final
|
|
||||||
* image is rendered. This allow to combine background graphics
|
|
||||||
* and only do blooming on certain objects param use32bitFBO does
|
|
||||||
* fbo use higher precision than 16bits.
|
|
||||||
*/
|
|
||||||
public Bloom(int FBO_W, int FBO_H, boolean hasDepth, boolean useBlending, boolean use32bitFBO){
|
|
||||||
initialize(FBO_W, FBO_H, null, hasDepth, useBlending, use32bitFBO);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EXPERT FUNCTIONALITY. no error checking. Use this only if you know what
|
|
||||||
* you are doing. Remember that bloom.capture() clear the screen so use
|
|
||||||
* continue instead if that is a problem.
|
|
||||||
* <p>
|
|
||||||
* Initialize bloom class that capsulate original scene capturate,
|
|
||||||
* tresholding, gaussian blurring and blending.
|
|
||||||
* <p>
|
|
||||||
* * @param sceneIsCapturedHere diposing is user responsibility.
|
|
||||||
*
|
|
||||||
* @param FBO_W
|
|
||||||
* @param FBO_H how big fbo is used for bloom texture, smaller = more blur and
|
|
||||||
* lot faster but aliasing can be problem
|
|
||||||
* @param useBlending does fbo need alpha channel and is blending enabled when final
|
|
||||||
* image is rendered. This allow to combine background graphics
|
|
||||||
* and only do blooming on certain objects param use32bitFBO does
|
|
||||||
* fbo use higher precision than 16bits.
|
|
||||||
*/
|
|
||||||
public Bloom(int FBO_W, int FBO_H, FrameBuffer sceneIsCapturedHere, boolean useBlending, boolean use32bitFBO){
|
|
||||||
initialize(FBO_W, FBO_H, sceneIsCapturedHere, false, useBlending, use32bitFBO);
|
|
||||||
disposeFBO = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initialize(int FBO_W, int FBO_H, FrameBuffer fbo, boolean hasDepth, boolean useBlending, boolean use32bitFBO){
|
|
||||||
blending = useBlending;
|
|
||||||
Format format;
|
|
||||||
|
|
||||||
if(use32bitFBO){
|
|
||||||
if(useBlending){
|
|
||||||
format = Format.RGBA8888;
|
|
||||||
}else{
|
|
||||||
format = Format.RGB888;
|
|
||||||
}
|
|
||||||
|
|
||||||
}else{
|
|
||||||
if(useBlending){
|
|
||||||
format = Format.RGBA4444;
|
|
||||||
}else{
|
|
||||||
format = Format.RGB565;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(fbo == null){
|
|
||||||
frameBuffer = new FrameBuffer(format, Core.graphics.getWidth(), Core.graphics.getHeight(), hasDepth);
|
|
||||||
}else{
|
|
||||||
frameBuffer = fbo;
|
|
||||||
}
|
|
||||||
|
|
||||||
pingPongBuffer1 = new FrameBuffer(format, FBO_W, FBO_H, false);
|
|
||||||
|
|
||||||
pingPongBuffer2 = new FrameBuffer(format, FBO_W, FBO_H, false);
|
|
||||||
|
|
||||||
original = frameBuffer.getTexture();
|
|
||||||
pingPongTex1 = pingPongBuffer1.getTexture();
|
|
||||||
pingPongTex2 = pingPongBuffer2.getTexture();
|
|
||||||
|
|
||||||
fullScreenQuad = createFullScreenQuad();
|
|
||||||
final String alpha = useBlending ? "alpha_" : "";
|
|
||||||
|
|
||||||
bloomShader = createShader("screenspace", alpha + "bloom");
|
|
||||||
|
|
||||||
if(useAlphaChannelAsMask){
|
|
||||||
tresholdShader = createShader("screenspace", "maskedtreshold");
|
|
||||||
}else{
|
|
||||||
tresholdShader = createShader("screenspace", alpha + "threshold");
|
|
||||||
}
|
|
||||||
|
|
||||||
blurShader = createShader("blurspace", alpha + "gaussian");
|
|
||||||
|
|
||||||
setSize(FBO_W, FBO_H);
|
|
||||||
setBloomIntesity(2.5f);
|
|
||||||
setOriginalIntesity(0.8f);
|
|
||||||
setThreshold(0.5f);
|
|
||||||
|
|
||||||
bloomShader.begin();
|
|
||||||
bloomShader.setUniformi("u_texture0", 0);
|
|
||||||
bloomShader.setUniformi("u_texture1", 1);
|
|
||||||
bloomShader.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set clearing color for capturing buffer
|
|
||||||
*
|
|
||||||
* @param r
|
|
||||||
* @param g
|
|
||||||
* @param b
|
|
||||||
* @param a
|
|
||||||
*/
|
|
||||||
public void setClearColor(float r, float g, float b, float a){
|
|
||||||
this.r = r;
|
|
||||||
this.g = g;
|
|
||||||
this.b = b;
|
|
||||||
this.a = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this before rendering scene.
|
|
||||||
*/
|
|
||||||
public void capture(){
|
|
||||||
if(!capturing){
|
|
||||||
capturing = true;
|
|
||||||
frameBuffer.begin();
|
|
||||||
Gl.clearColor(r, g, b, a);
|
|
||||||
Gl.clear(Gl.colorBufferBit);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pause capturing to fbo.
|
|
||||||
*/
|
|
||||||
public void capturePause(){
|
|
||||||
if(capturing){
|
|
||||||
capturing = false;
|
|
||||||
frameBuffer.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Start capturing again after pause, no clearing is done to framebuffer */
|
|
||||||
public void captureContinue(){
|
|
||||||
if(!capturing){
|
|
||||||
capturing = true;
|
|
||||||
frameBuffer.begin();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this after scene. Renders the bloomed scene.
|
|
||||||
*/
|
|
||||||
public void render(){
|
|
||||||
if(capturing){
|
|
||||||
capturing = false;
|
|
||||||
frameBuffer.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
Gl.disable(Gl.blend);
|
|
||||||
Gl.disable(Gl.depthTest);
|
|
||||||
Gl.depthMask(false);
|
|
||||||
|
|
||||||
gaussianBlur();
|
|
||||||
|
|
||||||
if(blending){
|
|
||||||
Gl.enable(Gl.blend);
|
|
||||||
Gl.blendFunc(Gl.srcAlpha, Gl.oneMinusSrcAlpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
pingPongTex1.bind(1);
|
|
||||||
original.bind(0);
|
|
||||||
|
|
||||||
bloomShader.begin();
|
|
||||||
fullScreenQuad.render(bloomShader, Gl.triangleFan);
|
|
||||||
bloomShader.end();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void gaussianBlur(){
|
|
||||||
|
|
||||||
// cut bright areas of the picture and blit to smaller fbo
|
|
||||||
|
|
||||||
original.bind(0);
|
|
||||||
pingPongBuffer1.begin();
|
|
||||||
tresholdShader.begin();
|
|
||||||
fullScreenQuad.render(tresholdShader, Gl.triangleFan, 0, 4);
|
|
||||||
tresholdShader.end();
|
|
||||||
pingPongBuffer1.end();
|
|
||||||
|
|
||||||
for(int i = 0; i < blurPasses; i++){
|
|
||||||
|
|
||||||
pingPongTex1.bind(0);
|
|
||||||
|
|
||||||
// horizontal
|
|
||||||
pingPongBuffer2.begin();
|
|
||||||
blurShader.begin();
|
|
||||||
blurShader.setUniformf("dir", 1f, 0f);
|
|
||||||
fullScreenQuad.render(blurShader, Gl.triangleFan, 0, 4);
|
|
||||||
blurShader.end();
|
|
||||||
pingPongBuffer2.end();
|
|
||||||
|
|
||||||
pingPongTex2.bind(0);
|
|
||||||
// vertical
|
|
||||||
pingPongBuffer1.begin();
|
|
||||||
blurShader.begin();
|
|
||||||
blurShader.setUniformf("dir", 0f, 1f);
|
|
||||||
fullScreenQuad.render(blurShader, Gl.triangleFan, 0, 4);
|
|
||||||
blurShader.end();
|
|
||||||
pingPongBuffer1.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set intensity for bloom. higher mean more brightening for spots that are
|
|
||||||
* over threshold
|
|
||||||
*
|
|
||||||
* @param intensity multiplier for blurred texture in combining phase. must be
|
|
||||||
* positive.
|
|
||||||
*/
|
|
||||||
public void setBloomIntesity(float intensity){
|
|
||||||
bloomIntensity = intensity;
|
|
||||||
bloomShader.begin();
|
|
||||||
bloomShader.setUniformf("BloomIntensity", intensity);
|
|
||||||
bloomShader.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* set intensity for original scene. under 1 mean darkening and over 1 means
|
|
||||||
* lightening
|
|
||||||
*
|
|
||||||
* @param intensity multiplier for captured texture in combining phase. must be
|
|
||||||
* positive.
|
|
||||||
*/
|
|
||||||
public void setOriginalIntesity(float intensity){
|
|
||||||
originalIntensity = intensity;
|
|
||||||
bloomShader.begin();
|
|
||||||
bloomShader.setUniformf("OriginalIntensity", intensity);
|
|
||||||
bloomShader.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Treshold for bright parts. everything under threshold is clamped to 0
|
|
||||||
*
|
|
||||||
* @param threshold must be in range 0..1
|
|
||||||
*/
|
|
||||||
public void setThreshold(float threshold){
|
|
||||||
this.threshold = threshold;
|
|
||||||
tresholdShader.begin();
|
|
||||||
tresholdShader.setUniformf("threshold", threshold, 1f / (1 - threshold));
|
|
||||||
tresholdShader.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSize(int FBO_W, int FBO_H){
|
|
||||||
w = FBO_W;
|
|
||||||
h = FBO_H;
|
|
||||||
blurShader.begin();
|
|
||||||
blurShader.setUniformf("size", FBO_W, FBO_H);
|
|
||||||
blurShader.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call this when application is exiting.
|
|
||||||
*/
|
|
||||||
public void dispose(){
|
|
||||||
try{
|
|
||||||
if(disposeFBO) frameBuffer.dispose();
|
|
||||||
|
|
||||||
fullScreenQuad.dispose();
|
|
||||||
|
|
||||||
pingPongBuffer1.dispose();
|
|
||||||
pingPongBuffer2.dispose();
|
|
||||||
|
|
||||||
blurShader.dispose();
|
|
||||||
bloomShader.dispose();
|
|
||||||
tresholdShader.dispose();
|
|
||||||
}catch(Throwable ignored){
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Mesh createFullScreenQuad(){
|
|
||||||
float[] verts = {-1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1};
|
|
||||||
Mesh tmpMesh = new Mesh(true, 4, 0,
|
|
||||||
new VertexAttribute(Usage.position, 2, "a_position"),
|
|
||||||
new VertexAttribute(Usage.textureCoordinates, 2, "a_texCoord0")
|
|
||||||
);
|
|
||||||
|
|
||||||
tmpMesh.setVertices(verts);
|
|
||||||
return tmpMesh;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Shader createShader(String vertexName, String fragmentName){
|
|
||||||
String vertexShader = Core.files.internal("bloomshaders/" + vertexName + ".vertex.glsl").readString();
|
|
||||||
String fragmentShader = Core.files.internal("bloomshaders/" + fragmentName + ".fragment.glsl").readString();
|
|
||||||
return new Shader(vertexShader, fragmentShader);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -125,7 +125,7 @@ public class OverlayRenderer{
|
|||||||
if(tile != null && tile.block() != Blocks.air && tile.getTeam() == player.getTeam()){
|
if(tile != null && tile.block() != Blocks.air && tile.getTeam() == player.getTeam()){
|
||||||
tile.block().drawSelect(tile);
|
tile.block().drawSelect(tile);
|
||||||
|
|
||||||
if(Core.input.keyDown(Binding.rotateplaced) && tile.block().rotate){
|
if(Core.input.keyDown(Binding.rotateplaced) && tile.block().rotate && tile.interactable(player.getTeam())){
|
||||||
control.input.drawArrow(tile.block(), tile.x, tile.y, tile.rotation(), true);
|
control.input.drawArrow(tile.block(), tile.x, tile.y, tile.rotation(), true);
|
||||||
Draw.color(Pal.accent, 0.3f + Mathf.absin(4f, 0.2f));
|
Draw.color(Pal.accent, 0.3f + Mathf.absin(4f, 0.2f));
|
||||||
Fill.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize/2f);
|
Fill.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize/2f);
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
cursorType = ui.unloadCursor;
|
cursorType = ui.unloadCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isPlacing() && Math.abs(Core.input.axisTap(Binding.rotate)) > 0 && Core.input.keyDown(Binding.rotateplaced) && cursor.block().rotate){
|
if(cursor.interactable(player.getTeam()) && !isPlacing() && Math.abs(Core.input.axisTap(Binding.rotate)) > 0 && Core.input.keyDown(Binding.rotateplaced) && cursor.block().rotate){
|
||||||
Call.rotateBlock(player, cursor, Core.input.axisTap(Binding.rotate) > 0);
|
Call.rotateBlock(player, cursor, Core.input.axisTap(Binding.rotate) > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void removeRequest(BuildRequest request){
|
void removeRequest(BuildRequest request){
|
||||||
selectRequests.removeValue(request, true);
|
selectRequests.remove(request, true);
|
||||||
if(!request.breaking){
|
if(!request.breaking){
|
||||||
removals.add(request);
|
removals.add(request);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import org.mozilla.javascript.*;
|
|||||||
public class Scripts implements Disposable{
|
public class Scripts implements Disposable{
|
||||||
private final Array<String> blacklist = Array.with("net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk",
|
private final Array<String> blacklist = Array.with("net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk",
|
||||||
"runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system",
|
"runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system",
|
||||||
".awt", "socket", "classloader", "oracle");
|
".awt", "socket", "classloader", "oracle", "invoke");
|
||||||
private final Array<String> whitelist = Array.with("mindustry.net");
|
private final Array<String> whitelist = Array.with("mindustry.net");
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final String wrapper;
|
private final String wrapper;
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ public class Administration{
|
|||||||
if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){
|
if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){
|
||||||
player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2);
|
player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2);
|
||||||
}
|
}
|
||||||
player.getInfo().lastSentMessage = message;
|
|
||||||
return null;
|
return null;
|
||||||
}else{
|
}else{
|
||||||
player.getInfo().messageInfractions = 0;
|
player.getInfo().messageInfractions = 0;
|
||||||
@@ -191,7 +190,7 @@ public class Administration{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bannedIPs.removeValue(ip, false);
|
bannedIPs.remove(ip, false);
|
||||||
|
|
||||||
if(found){
|
if(found){
|
||||||
save();
|
save();
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import mindustry.ctype.ContentType;
|
|||||||
import mindustry.entities.*;
|
import mindustry.entities.*;
|
||||||
import mindustry.entities.Effects.*;
|
import mindustry.entities.Effects.*;
|
||||||
import mindustry.entities.type.*;
|
import mindustry.entities.type.*;
|
||||||
import mindustry.entities.units.Statuses.*;
|
import mindustry.entities.units.*;
|
||||||
|
|
||||||
public class StatusEffect extends MappableContent{
|
public class StatusEffect extends MappableContent{
|
||||||
/** Damage dealt by the unit with the effect. */
|
/** Damage dealt by the unit with the effect. */
|
||||||
|
|||||||
@@ -62,6 +62,10 @@ public class GameOverDialog extends FloatingDialog{
|
|||||||
t.row();
|
t.row();
|
||||||
t.add(Core.bundle.format("stat.deconstructed", state.stats.buildingsDeconstructed));
|
t.add(Core.bundle.format("stat.deconstructed", state.stats.buildingsDeconstructed));
|
||||||
t.row();
|
t.row();
|
||||||
|
if(control.saves.getCurrent() != null){
|
||||||
|
t.add(Core.bundle.format("stat.playtime", control.saves.getCurrent().getPlayTime()));
|
||||||
|
t.row();
|
||||||
|
}
|
||||||
if(world.isZone() && !state.stats.itemsDelivered.isEmpty()){
|
if(world.isZone() && !state.stats.itemsDelivered.isEmpty()){
|
||||||
t.add("$stat.delivered");
|
t.add("$stat.delivered");
|
||||||
t.row();
|
t.row();
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ public class JoinDialog extends FloatingDialog{
|
|||||||
|
|
||||||
inner.addImageButton(Icon.trash, Styles.emptyi, () -> {
|
inner.addImageButton(Icon.trash, Styles.emptyi, () -> {
|
||||||
ui.showConfirm("$confirm", "$server.delete", () -> {
|
ui.showConfirm("$confirm", "$server.delete", () -> {
|
||||||
servers.removeValue(server, true);
|
servers.remove(server, true);
|
||||||
saveServers();
|
saveServers();
|
||||||
setupRemote();
|
setupRemote();
|
||||||
refreshRemote();
|
refreshRemote();
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class ModsDialog extends FloatingDialog{
|
|||||||
void modError(Throwable error){
|
void modError(Throwable error){
|
||||||
ui.loadfrag.hide();
|
ui.loadfrag.hide();
|
||||||
|
|
||||||
if(Strings.getCauses(error).contains(t -> t.getMessage() != null && (t.getMessage().contains("SSL") || t.getMessage().contains("protocol")))){
|
if(Strings.getCauses(error).contains(t -> t.getMessage() != null && (t.getMessage().contains("trust anchor") || t.getMessage().contains("SSL") || t.getMessage().contains("protocol")))){
|
||||||
ui.showErrorMessage("$feature.unsupported");
|
ui.showErrorMessage("$feature.unsupported");
|
||||||
}else{
|
}else{
|
||||||
ui.showException(error);
|
ui.showException(error);
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
|||||||
}
|
}
|
||||||
})));
|
})));
|
||||||
|
|
||||||
if(!ios){
|
if(!mobile){
|
||||||
t.row();
|
t.row();
|
||||||
t.addImageTextButton("$data.openfolder", Icon.folder, style, () -> Core.app.openFolder(Core.settings.getDataDirectory().absolutePath()));
|
t.addImageTextButton("$data.openfolder", Icon.folder, style, () -> Core.app.openFolder(Core.settings.getDataDirectory().absolutePath()));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ public class ItemModule extends BlockModule{
|
|||||||
private int[] items = new int[content.items().size];
|
private int[] items = new int[content.items().size];
|
||||||
private int total;
|
private int total;
|
||||||
|
|
||||||
|
// Make the take() loop persistent so it does not return the same item twice in a row unless there is nothing else to return.
|
||||||
|
protected int takeRotation;
|
||||||
|
|
||||||
public void forEach(ItemConsumer cons){
|
public void forEach(ItemConsumer cons){
|
||||||
for(int i = 0; i < items.length; i++){
|
for(int i = 0; i < items.length; i++){
|
||||||
if(items[i] > 0){
|
if(items[i] > 0){
|
||||||
@@ -66,21 +69,27 @@ public class ItemModule extends BlockModule{
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item first(){
|
public Item first(){ // fixme: entangle with take()
|
||||||
for(int i = 0; i < items.length; i++){
|
for(int i = 0; i < items.length; i++){
|
||||||
if(items[i] > 0) return content.item(i);
|
if(items[i] > 0){
|
||||||
|
return content.item(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item take(){
|
public Item take(){
|
||||||
if(first() == null) return null;
|
for(int i = 0; i < items.length; i++){
|
||||||
|
int index = (i + takeRotation);
|
||||||
int id = first().id;
|
if(index >= items.length) index -= items.length; //conditional instead of mod
|
||||||
items[id]--;
|
if(items[index] > 0){
|
||||||
|
items[index] --;
|
||||||
total --;
|
total --;
|
||||||
|
takeRotation = index + 1;
|
||||||
return content.item(id);
|
return content.item(index % items.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int get(Item item){
|
public int get(Item item){
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
org.gradle.daemon=true
|
org.gradle.daemon=true
|
||||||
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
org.gradle.jvmargs=-Xms256m -Xmx1024m
|
||||||
archash=649641d8936160221ce24c47f5b0ad10606de289
|
archash=1817bb22ac7680700fe780816940f4217a1f7e07
|
||||||
|
|||||||
@@ -653,18 +653,10 @@ public class ServerControl implements ApplicationListener{
|
|||||||
});
|
});
|
||||||
|
|
||||||
handler.register("unban", "<ip/ID>", "Completely unban a person by IP or ID.", arg -> {
|
handler.register("unban", "<ip/ID>", "Completely unban a person by IP or ID.", arg -> {
|
||||||
if(arg[0].contains(".")){
|
if(netServer.admins.unbanPlayerIP(arg[0]) || netServer.admins.unbanPlayerID(arg[0])){
|
||||||
if(netServer.admins.unbanPlayerIP(arg[0])){
|
info("Unbanned player.", arg[0]);
|
||||||
info("Unbanned player by IP: {0}.", arg[0]);
|
|
||||||
}else{
|
}else{
|
||||||
err("That IP is not banned!");
|
err("That IP/ID is not banned!");
|
||||||
}
|
|
||||||
}else{
|
|
||||||
if(netServer.admins.unbanPlayerID(arg[0])){
|
|
||||||
info("Unbanned player by ID: {0}.", arg[0]);
|
|
||||||
}else{
|
|
||||||
err("That ID is not banned!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
12
servers.json
@@ -10,5 +10,17 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"address": "mindustry.ru"
|
"address": "mindustry.ru"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "mindustry.io"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "mindustry.io:1000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "mindustry.io:2000"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"address": "mindustry.io:3000"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||