Merge branch 'master' of https://github.com/Anuken/Mindustry
@@ -4,12 +4,27 @@ import java.lang.annotation.*;
|
|||||||
|
|
||||||
public class Annotations{
|
public class Annotations{
|
||||||
|
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
/** Indicates that a method should always call its super version. */
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface CallSuper{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Annotation that allows overriding CallSuper annotation. To be used on method that overrides method with CallSuper annotation from parent class.*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface OverrideCallSuper {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates that a method return or field can be null.*/
|
||||||
|
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface Nullable{
|
public @interface Nullable{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Indicates that a method return or field cannot be null.*/
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD})
|
@Target({ElementType.METHOD, ElementType.FIELD})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface NonNull{
|
public @interface NonNull{
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package io.anuke.annotations;
|
||||||
|
|
||||||
|
import com.sun.source.util.TreePath;
|
||||||
|
import com.sun.source.util.Trees;
|
||||||
|
import com.sun.tools.javac.tree.JCTree;
|
||||||
|
import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
|
||||||
|
import io.anuke.annotations.Annotations.OverrideCallSuper;
|
||||||
|
|
||||||
|
import javax.annotation.processing.*;
|
||||||
|
import javax.lang.model.SourceVersion;
|
||||||
|
import javax.lang.model.element.Element;
|
||||||
|
import javax.lang.model.element.TypeElement;
|
||||||
|
import javax.tools.Diagnostic.Kind;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
@SupportedAnnotationTypes("java.lang.Override")
|
||||||
|
public class CallSuperAnnotationProcessor extends AbstractProcessor{
|
||||||
|
private Trees trees;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init (ProcessingEnvironment pe) {
|
||||||
|
super.init(pe);
|
||||||
|
trees = Trees.instance(pe);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean process (Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||||
|
for (Element e : roundEnv.getElementsAnnotatedWith(Override.class)) {
|
||||||
|
if (e.getAnnotation(OverrideCallSuper.class) != null) return false;
|
||||||
|
|
||||||
|
CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner();
|
||||||
|
codeScanner.setMethodName(e.getSimpleName().toString());
|
||||||
|
|
||||||
|
TreePath tp = trees.getPath(e.getEnclosingElement());
|
||||||
|
codeScanner.scan(tp, trees);
|
||||||
|
|
||||||
|
if (codeScanner.isCallSuperUsed()) {
|
||||||
|
List list = codeScanner.getMethod().getBody().getStatements();
|
||||||
|
|
||||||
|
if (!doesCallSuper(list, codeScanner.getMethodName())) {
|
||||||
|
processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.getMethodName() + "' must explicitly call super method from its parent class.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean doesCallSuper (List list, String methodName) {
|
||||||
|
for (Object object : list) {
|
||||||
|
if (object instanceof JCTree.JCExpressionStatement) {
|
||||||
|
JCTree.JCExpressionStatement expr = (JCExpressionStatement) object;
|
||||||
|
String exprString = expr.toString();
|
||||||
|
if (exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SourceVersion getSupportedSourceVersion () {
|
||||||
|
return SourceVersion.RELEASE_8;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package io.anuke.annotations;
|
||||||
|
|
||||||
|
import com.sun.source.tree.*;
|
||||||
|
import com.sun.source.util.TreePathScanner;
|
||||||
|
import com.sun.source.util.Trees;
|
||||||
|
import com.sun.tools.javac.code.Scope;
|
||||||
|
import com.sun.tools.javac.code.Symbol;
|
||||||
|
import com.sun.tools.javac.code.Symbol.MethodSymbol;
|
||||||
|
import com.sun.tools.javac.code.Type.ClassType;
|
||||||
|
import com.sun.tools.javac.tree.JCTree.JCIdent;
|
||||||
|
import com.sun.tools.javac.tree.JCTree.JCTypeApply;
|
||||||
|
import io.anuke.annotations.Annotations.CallSuper;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
|
||||||
|
class CodeAnalyzerTreeScanner extends TreePathScanner<Object, Trees> {
|
||||||
|
private String methodName;
|
||||||
|
private MethodTree method;
|
||||||
|
private boolean callSuperUsed;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitClass (ClassTree classTree, Trees trees) {
|
||||||
|
Tree extendTree = classTree.getExtendsClause();
|
||||||
|
|
||||||
|
if (extendTree instanceof JCTypeApply) { //generic classes case
|
||||||
|
JCTypeApply generic = (JCTypeApply) extendTree;
|
||||||
|
extendTree = generic.clazz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extendTree instanceof JCIdent) {
|
||||||
|
JCIdent tree = (JCIdent) extendTree;
|
||||||
|
Scope members = tree.sym.members();
|
||||||
|
|
||||||
|
if (checkScope(members))
|
||||||
|
return super.visitClass(classTree, trees);
|
||||||
|
|
||||||
|
if (checkSuperTypes((ClassType) tree.type))
|
||||||
|
return super.visitClass(classTree, trees);
|
||||||
|
|
||||||
|
}
|
||||||
|
callSuperUsed = false;
|
||||||
|
|
||||||
|
return super.visitClass(classTree, trees);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkSuperTypes (ClassType type) {
|
||||||
|
if (type.supertype_field != null && type.supertype_field.tsym != null) {
|
||||||
|
if (checkScope(type.supertype_field.tsym.members()))
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return checkSuperTypes((ClassType) type.supertype_field);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkScope (Scope members) {
|
||||||
|
for (Symbol s : members.getElements()) {
|
||||||
|
if (s instanceof MethodSymbol) {
|
||||||
|
MethodSymbol ms = (MethodSymbol) s;
|
||||||
|
|
||||||
|
if (ms.getSimpleName().toString().equals(methodName)) {
|
||||||
|
Annotation annotation = ms.getAnnotation(CallSuper.class);
|
||||||
|
if (annotation != null) {
|
||||||
|
callSuperUsed = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object visitMethod (MethodTree methodTree, Trees trees) {
|
||||||
|
if (methodTree.getName().toString().equals(methodName))
|
||||||
|
method = methodTree;
|
||||||
|
|
||||||
|
return super.visitMethod(methodTree, trees);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMethodName (String methodName) {
|
||||||
|
this.methodName = methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getMethodName () {
|
||||||
|
return methodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodTree getMethod () {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isCallSuperUsed () {
|
||||||
|
return callSuperUsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,9 +13,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
||||||
@SupportedAnnotationTypes({
|
@SupportedAnnotationTypes("io.anuke.annotations.Annotations.Serialize")
|
||||||
"io.anuke.annotations.Annotations.Serialize"
|
|
||||||
})
|
|
||||||
public class SerializeAnnotationProcessor extends AbstractProcessor{
|
public class SerializeAnnotationProcessor extends AbstractProcessor{
|
||||||
/** Target class name. */
|
/** Target class name. */
|
||||||
private static final String className = "Serialization";
|
private static final String className = "Serialization";
|
||||||
@@ -44,20 +42,10 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
|||||||
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC);
|
||||||
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(RemoteMethodAnnotationProcessor.autogenWarning);
|
||||||
|
|
||||||
|
|
||||||
MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
||||||
|
|
||||||
TypeName jsonType = ClassName.bestGuess("io.anuke.arc.util.serialization.Json");
|
|
||||||
TypeName jsonValueType = ClassName.bestGuess("io.anuke.arc.util.serialization.JsonValue");
|
|
||||||
TypeName ubJsonWriterType = ClassName.bestGuess("io.anuke.arc.util.serialization.UBJsonWriter");
|
|
||||||
TypeName ubJsonReaderType = ClassName.bestGuess("io.anuke.arc.util.serialization.UBJsonReader");
|
|
||||||
|
|
||||||
classBuilder.addField(jsonType, "bjson", Modifier.STATIC, Modifier.PRIVATE);
|
|
||||||
classBuilder.addField(ubJsonReaderType, "bjsonReader", Modifier.STATIC, Modifier.PRIVATE);
|
|
||||||
classBuilder.addStaticBlock(CodeBlock.builder()
|
|
||||||
.addStatement("bjson = new " + jsonType + "()")
|
|
||||||
.addStatement("bjsonReader = new " + ubJsonReaderType + "()")
|
|
||||||
.build());
|
|
||||||
|
|
||||||
for(TypeElement elem : elements){
|
for(TypeElement elem : elements){
|
||||||
TypeName type = TypeName.get(elem.asType());
|
TypeName type = TypeName.get(elem.asType());
|
||||||
String simpleTypeName = type.toString().substring(type.toString().lastIndexOf('.') + 1);
|
String simpleTypeName = type.toString().substring(type.toString().lastIndexOf('.') + 1);
|
||||||
@@ -79,19 +67,7 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
|||||||
.addException(IOException.class)
|
.addException(IOException.class)
|
||||||
.addModifiers(Modifier.PUBLIC);
|
.addModifiers(Modifier.PUBLIC);
|
||||||
|
|
||||||
MethodSpec.Builder jsonWriteMethod = MethodSpec.methodBuilder("write" + simpleTypeName + "Json")
|
|
||||||
.returns(void.class)
|
|
||||||
.addParameter(jsonType, "json")
|
|
||||||
.addParameter(type, "object")
|
|
||||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
|
||||||
|
|
||||||
MethodSpec.Builder jsonReadMethod = MethodSpec.methodBuilder("read" + simpleTypeName + "Json")
|
|
||||||
.returns(type)
|
|
||||||
.addParameter(jsonValueType, "value")
|
|
||||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC);
|
|
||||||
|
|
||||||
readMethod.addStatement("$L object = new $L()", type, type);
|
readMethod.addStatement("$L object = new $L()", type, type);
|
||||||
jsonReadMethod.addStatement("$L object = new $L()", type, type);
|
|
||||||
|
|
||||||
List<VariableElement> fields = ElementFilter.fieldsIn(Utils.elementUtils.getAllMembers(elem));
|
List<VariableElement> fields = ElementFilter.fieldsIn(Utils.elementUtils.getAllMembers(elem));
|
||||||
for(VariableElement field : fields){
|
for(VariableElement field : fields){
|
||||||
@@ -105,9 +81,6 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
|||||||
if(field.asType().getKind().isPrimitive()){
|
if(field.asType().getKind().isPrimitive()){
|
||||||
writeMethod.addStatement("stream.write" + capName + "(object." + name + ")");
|
writeMethod.addStatement("stream.write" + capName + "(object." + name + ")");
|
||||||
readMethod.addStatement("object." + name + "= stream.read" + capName + "()");
|
readMethod.addStatement("object." + name + "= stream.read" + capName + "()");
|
||||||
|
|
||||||
jsonWriteMethod.addStatement("json.writeValue(\"" + name + "\", object." + name + ")");
|
|
||||||
jsonReadMethod.addStatement("if(value.has(\"" + name + "\")) object." + name + "= value.get" + capName + "(\"" + name + "\")");
|
|
||||||
}else{
|
}else{
|
||||||
writeMethod.addStatement("io.anuke.arc.Core.settings.getSerializer(" + typeName + ".class).write(stream, object." + name + ")");
|
writeMethod.addStatement("io.anuke.arc.Core.settings.getSerializer(" + typeName + ".class).write(stream, object." + name + ")");
|
||||||
readMethod.addStatement("object." + name + " = (" + typeName + ")io.anuke.arc.Core.settings.getSerializer(" + typeName + ".class).read(stream)");
|
readMethod.addStatement("object." + name + " = (" + typeName + ")io.anuke.arc.Core.settings.getSerializer(" + typeName + ".class).read(stream)");
|
||||||
@@ -115,7 +88,6 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
readMethod.addStatement("return object");
|
readMethod.addStatement("return object");
|
||||||
jsonReadMethod.addStatement("return object");
|
|
||||||
|
|
||||||
serializer.addMethod(writeMethod.build());
|
serializer.addMethod(writeMethod.build());
|
||||||
serializer.addMethod(readMethod.build());
|
serializer.addMethod(readMethod.build());
|
||||||
@@ -130,32 +102,6 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{
|
|||||||
|
|
||||||
classBuilder.addMethod(writeMethod.build());
|
classBuilder.addMethod(writeMethod.build());
|
||||||
classBuilder.addMethod(readMethod.build());
|
classBuilder.addMethod(readMethod.build());
|
||||||
|
|
||||||
classBuilder.addMethod(jsonWriteMethod.build());
|
|
||||||
classBuilder.addMethod(jsonReadMethod.build());
|
|
||||||
|
|
||||||
MethodSpec.Builder binaryJsonWriteMethod = MethodSpec.methodBuilder("write" + simpleTypeName + "StreamJson")
|
|
||||||
.returns(void.class)
|
|
||||||
.addParameter(DataOutput.class, "stream")
|
|
||||||
.addParameter(type, "object")
|
|
||||||
.addException(IOException.class)
|
|
||||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
|
||||||
.addStatement("java.io.StringWriter output = new java.io.StringWriter()")
|
|
||||||
.addStatement("bjson.setWriter(output)")
|
|
||||||
.addStatement("bjson.writeObjectStart(" + type + ".class, " + type + ".class)")
|
|
||||||
.addStatement("write" + simpleTypeName + "Json(bjson, object)")
|
|
||||||
.addStatement("bjson.writeObjectEnd()")
|
|
||||||
.addStatement("stream.writeUTF(output.toString())");
|
|
||||||
|
|
||||||
MethodSpec.Builder binaryJsonReadMethod = MethodSpec.methodBuilder("read" + simpleTypeName + "StreamJson")
|
|
||||||
.returns(type)
|
|
||||||
.addParameter(DataInput.class, "stream")
|
|
||||||
.addException(IOException.class)
|
|
||||||
.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
|
|
||||||
.addStatement("return read" + simpleTypeName + "Json(bjson.fromJson(null, stream.readUTF()))");
|
|
||||||
|
|
||||||
classBuilder.addMethod(binaryJsonWriteMethod.build());
|
|
||||||
classBuilder.addMethod(binaryJsonReadMethod.build());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
classBuilder.addMethod(method.build());
|
classBuilder.addMethod(method.build());
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
io.anuke.annotations.RemoteMethodAnnotationProcessor
|
io.anuke.annotations.RemoteMethodAnnotationProcessor
|
||||||
io.anuke.annotations.SerializeAnnotationProcessor
|
io.anuke.annotations.SerializeAnnotationProcessor
|
||||||
io.anuke.annotations.StructAnnotationProcessor
|
io.anuke.annotations.StructAnnotationProcessor
|
||||||
|
io.anuke.annotations.CallSuperAnnotationProcessor
|
||||||
28
build.gradle
@@ -29,7 +29,7 @@ allprojects{
|
|||||||
arcHash = null
|
arcHash = null
|
||||||
|
|
||||||
debugged = {
|
debugged = {
|
||||||
return new File(projectDir.parent, '../debug').exists() && !project.hasProperty("release")
|
return new File(projectDir.parent, '../debug').exists() && !project.hasProperty("release") && project.hasProperty("args")
|
||||||
}
|
}
|
||||||
|
|
||||||
localArc = {
|
localArc = {
|
||||||
@@ -177,6 +177,31 @@ project(":core"){
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies{
|
dependencies{
|
||||||
|
if(System.properties["user.name"] == "anuke"){
|
||||||
|
task cleanGen{
|
||||||
|
doFirst{
|
||||||
|
delete{
|
||||||
|
delete "../core/src/io/anuke/mindustry/gen/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task copyGen{
|
||||||
|
doLast{
|
||||||
|
copy{
|
||||||
|
from("../core/build/generated/sources/annotationProcessor/java/main/io/anuke/mindustry/gen"){
|
||||||
|
include "**/*.java"
|
||||||
|
}
|
||||||
|
|
||||||
|
into "../core/src/io/anuke/mindustry/gen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compileJava.dependsOn(cleanGen)
|
||||||
|
compileJava.finalizedBy(copyGen)
|
||||||
|
}
|
||||||
|
|
||||||
compile arcModule("arc-core")
|
compile arcModule("arc-core")
|
||||||
compile arcModule("extensions:freetype")
|
compile arcModule("extensions:freetype")
|
||||||
compile arcModule("extensions:arcnet")
|
compile arcModule("extensions:arcnet")
|
||||||
@@ -227,6 +252,7 @@ project(":annotations"){
|
|||||||
|
|
||||||
dependencies{
|
dependencies{
|
||||||
compile 'com.squareup:javapoet:1.11.0'
|
compile 'com.squareup:javapoet:1.11.0'
|
||||||
|
compile files("${System.getProperty('java.home')}/../lib/tools.jar")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
core/assets-raw/sprites/ui/icons/icon-diagonal.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.8 KiB |
@@ -89,13 +89,8 @@ trace = Trace Player
|
|||||||
trace.playername = Player name: [accent]{0}
|
trace.playername = Player name: [accent]{0}
|
||||||
trace.ip = IP: [accent]{0}
|
trace.ip = IP: [accent]{0}
|
||||||
trace.id = Unique ID: [accent]{0}
|
trace.id = Unique ID: [accent]{0}
|
||||||
trace.android = Android Client: [accent]{0}
|
trace.mobile = Mobile Client: [accent]{0}
|
||||||
trace.modclient = Custom Client: [accent]{0}
|
trace.modclient = Custom Client: [accent]{0}
|
||||||
trace.totalblocksbroken = Total blocks broken: [accent]{0}
|
|
||||||
trace.structureblocksbroken = Structure blocks broken: [accent]{0}
|
|
||||||
trace.lastblockbroken = Last block broken: [accent]{0}
|
|
||||||
trace.totalblocksplaced = Total blocks placed: [accent]{0}
|
|
||||||
trace.lastblockplaced = Last block placed: [accent]{0}
|
|
||||||
invalidid = Invalid client ID! Submit a bug report.
|
invalidid = Invalid client ID! Submit a bug report.
|
||||||
server.bans = Bans
|
server.bans = Bans
|
||||||
server.bans.none = No banned players found!
|
server.bans.none = No banned players found!
|
||||||
@@ -199,6 +194,8 @@ editor.mapinfo = Map Info
|
|||||||
editor.author = Author:
|
editor.author = Author:
|
||||||
editor.description = Description:
|
editor.description = Description:
|
||||||
editor.waves = Waves:
|
editor.waves = Waves:
|
||||||
|
editor.rules = Rules:
|
||||||
|
editor.ingame = Edit In-Game
|
||||||
waves.title = Waves
|
waves.title = Waves
|
||||||
waves.remove = Remove
|
waves.remove = Remove
|
||||||
waves.never = <never>
|
waves.never = <never>
|
||||||
@@ -216,6 +213,8 @@ waves.copied = Waves copied.
|
|||||||
editor.default = [LIGHT_GRAY]<Default>
|
editor.default = [LIGHT_GRAY]<Default>
|
||||||
edit = Edit...
|
edit = Edit...
|
||||||
editor.name = Name:
|
editor.name = Name:
|
||||||
|
editor.spawn = Spawn Unit
|
||||||
|
editor.removeunit = Remove Unit
|
||||||
editor.teams = Teams
|
editor.teams = Teams
|
||||||
editor.elevation = Elevation
|
editor.elevation = Elevation
|
||||||
editor.errorload = Error loading file:\n[accent]{0}
|
editor.errorload = Error loading file:\n[accent]{0}
|
||||||
@@ -436,11 +435,11 @@ setting.fpscap.name = Max FPS
|
|||||||
setting.fpscap.none = None
|
setting.fpscap.none = None
|
||||||
setting.fpscap.text = {0} FPS
|
setting.fpscap.text = {0} FPS
|
||||||
setting.swapdiagonal.name = Always Diagonal Placement
|
setting.swapdiagonal.name = Always Diagonal Placement
|
||||||
setting.difficulty.training = training
|
setting.difficulty.training = Training
|
||||||
setting.difficulty.easy = easy
|
setting.difficulty.easy = Easy
|
||||||
setting.difficulty.normal = normal
|
setting.difficulty.normal = Normal
|
||||||
setting.difficulty.hard = hard
|
setting.difficulty.hard = Hard
|
||||||
setting.difficulty.insane = insane
|
setting.difficulty.insane = Insane
|
||||||
setting.difficulty.name = Difficulty:
|
setting.difficulty.name = Difficulty:
|
||||||
setting.screenshake.name = Screen Shake
|
setting.screenshake.name = Screen Shake
|
||||||
setting.effects.name = Display Effects
|
setting.effects.name = Display Effects
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
credits.text = Creato da [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[GRAY](Nel caso non te ne sia accorto, la traduzione del gioco non è completa.\n Chi di dovere sta lavorando più velocemente possibile per completarla!)
|
credits.text = Creato da [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[GRAY](Nel caso non te ne sia accorto, la traduzione del gioco non è completa.\n Chi di dovere sta lavorando più velocemente possibile per completarla! Un aiutino non sarebbe male!)
|
||||||
credits = Crediti
|
credits = Crediti
|
||||||
contributors = Translators and Contributors
|
contributors = Translators and Contributors
|
||||||
discord = Unisciti sul server discord di mindustry!
|
discord = Unisciti sul server discord di mindustry!
|
||||||
@@ -10,38 +10,38 @@ link.itch.io.description = pagina di itch.io con download per PC e versione web
|
|||||||
link.google-play.description = Elenco di Google Play Store
|
link.google-play.description = Elenco di Google Play Store
|
||||||
link.wiki.description = wiki ufficiale di Mindustry
|
link.wiki.description = wiki ufficiale di Mindustry
|
||||||
linkfail = Impossibile aprire il link! L'URL è stato copiato nella tua bacheca.
|
linkfail = Impossibile aprire il link! L'URL è stato copiato nella tua bacheca.
|
||||||
screenshot = Screenshot saved to {0}
|
screenshot = Screenshot salvato a {0}
|
||||||
screenshot.invalid = Map too large, potentially not enough memory for screenshot.
|
screenshot.invalid = Mappa troppo grossa, probabilmente non c'è abbastanza memoria libera.
|
||||||
gameover = Il nucleo è stato distrutto.
|
gameover = Il nucleo è stato distrutto.
|
||||||
gameover.pvp = The[accent] {0}[] team is victorious!
|
gameover.pvp = La squadra [accent] {0}[] ha vinto!
|
||||||
highscore = [YELLOW]Nuovo record!
|
highscore = [YELLOW]Nuovo record!
|
||||||
stat.wave = Waves Defeated:[accent] {0}
|
stat.wave = Ondate sconfitte:[accent] {0}
|
||||||
stat.enemiesDestroyed = Enemies Destroyed:[accent] {0}
|
stat.enemiesDestroyed = Nemici distrutti:[accent] {0}
|
||||||
stat.built = Buildings Built:[accent] {0}
|
stat.built = Costruzioni erette:[accent] {0}
|
||||||
stat.destroyed = Buildings Destroyed:[accent] {0}
|
stat.destroyed = Costruzioni distrutte:[accent] {0}
|
||||||
stat.deconstructed = Buildings Deconstructed:[accent] {0}
|
stat.deconstructed = Costruzioni smontate:[accent] {0}
|
||||||
stat.delivered = Resources Launched:
|
stat.delivered = Riorse lanciate:
|
||||||
stat.rank = Final Rank: [accent]{0}
|
stat.rank = Livello finale: [accent]{0}
|
||||||
placeline = You have selected a block.\nYou can[accent] place in a line[] by[accent] holding down your finger for a few seconds[] and dragging in a direction.\nTry it.
|
placeline = Hai appena selezionato un blocco.\nOra puoi[accent] piazzarne una linea[] eseguendo[accent] una lunga pressione[] e poi trascinando in ogni direzione.\nProva!
|
||||||
removearea = You have selected removal mode.\nYou can[accent] remove blocks in a rectangle[] by[accent] holding down your finger for a few seconds[] and dragging.\nTry it.
|
removearea = Hai appena selezionato la modalità distruzione.\nOra puoi[accent] rimuovere blocchi in una certa zona [] eseguendo[accent] una lunga pressione[] e poi trascinando in ogni direzione.\nProva!
|
||||||
launcheditems = [accent]Launched Items
|
launcheditems = [accent]Oggetti lanciati
|
||||||
map.delete = Sei sicuro di voler eliminare questa mappa"[accent]{0}[]"?
|
map.delete = Sei sicuro di voler eliminare questa mappa"[accent]{0}[]"?
|
||||||
level.highscore = Miglior punteggio: [accent]{0}
|
level.highscore = Miglior punteggio: [accent]{0}
|
||||||
level.select = Selezione del livello
|
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]LEAVE DROP POINT IMMEDIATELY[] ]\nannihilation imminent
|
nearpoint = [[ [scarlet]LACIA LA ZONA NEMICA IMMEDIATAMENTE[] ]\nautodistruzione imminente
|
||||||
outofbounds = [[ OUT OF BOUNDS ]\n[]self-destruct in {0}
|
outofbounds = [[ SEI FUORI DAL MONDO ]\n[]Auto-distruzione in {0}
|
||||||
database = Core Database
|
database = Database nucleo
|
||||||
savegame = Salva
|
savegame = Salva
|
||||||
loadgame = Carica
|
loadgame = Carica
|
||||||
joingame = Unisciti al gioco
|
joingame = Unisciti al gioco
|
||||||
addplayers = Aggiungi/rimuovi giocatori
|
addplayers = Aggiungi/rimuovi giocatori
|
||||||
customgame = Gioco personalizzato
|
customgame = Gioco personalizzato
|
||||||
newgame = New Game
|
newgame = Nuova partita
|
||||||
none = <Niente . . . >
|
none = <Niente . . . >
|
||||||
minimap = Minimap
|
minimap = Minimapa
|
||||||
close = Chiuso
|
close = Chiuso
|
||||||
quit = Esci
|
quit = Esci
|
||||||
maps = Mappe
|
maps = Mappe
|
||||||
@@ -49,14 +49,14 @@ continue = Continua
|
|||||||
maps.none = [LIGHT_GRAY]Nessuna mappa trovata!
|
maps.none = [LIGHT_GRAY]Nessuna mappa trovata!
|
||||||
about.button = Info
|
about.button = Info
|
||||||
name = Nome:
|
name = Nome:
|
||||||
noname = Pick a[accent] player name[] first.
|
noname = Scegli un [accent] nome[] prima di unirti.
|
||||||
filename = File Name:
|
filename = Nome file:
|
||||||
unlocked = Nuovo blocco scoperto!
|
unlocked = Nuovo blocco scoperto!
|
||||||
completed = [accent]Completed
|
completed = [accent]Completo
|
||||||
techtree = Tech Tree
|
techtree = Albero scoperta
|
||||||
research.list = [LIGHT_GRAY]Research:
|
research.list = [LIGHT_GRAY]Ricerca:
|
||||||
research = Research
|
research = Ricerca
|
||||||
researched = [LIGHT_GRAY]{0} researched.
|
researched = [LIGHT_GRAY]{0} cercati.
|
||||||
players = {0} giocatori online
|
players = {0} giocatori online
|
||||||
players.single = {0} giocatori online
|
players.single = {0} giocatori online
|
||||||
server.closing = [accent]Chiusura server ...
|
server.closing = [accent]Chiusura server ...
|
||||||
@@ -74,7 +74,7 @@ server.kicked.gameover = Game over!
|
|||||||
host.info = Il pulsante [accent]hos [] ospita un server sulle porte [scarlet]6567[] e [scarlet]656.[] Chiunque sulla stessa [LIGHT_GRAY]connessione wifi o rete locale[] dovrebbe essere in grado di vedere il proprio server nel proprio elenco server.\n\n Se vuoi che le persone siano in grado di connettersi ovunque tramite IP, è richiesto il [accent]port forwarding[]. \n\n[LIGHT_GRAY]Nota: se qualcuno sta riscontrando problemi durante la connessione al gioco LAN, assicurati di aver consentito a Mindustry di accedere alla rete locale nelle impostazioni del firewall.
|
host.info = Il pulsante [accent]hos [] ospita un server sulle porte [scarlet]6567[] e [scarlet]656.[] Chiunque sulla stessa [LIGHT_GRAY]connessione wifi o rete locale[] dovrebbe essere in grado di vedere il proprio server nel proprio elenco server.\n\n Se vuoi che le persone siano in grado di connettersi ovunque tramite IP, è richiesto il [accent]port forwarding[]. \n\n[LIGHT_GRAY]Nota: se qualcuno sta riscontrando problemi durante la connessione al gioco LAN, assicurati di aver consentito a Mindustry di accedere alla rete locale nelle impostazioni del firewall.
|
||||||
join.info = Qui è possibile inserire un [accent]IP del server[] a cui connettersi, o scoprire [accento]un server sulla rete locale[] disponibile.\n Sono supportati sia il multiplayer LAN che WAN. \n\n[LIGHT_GRAY]Nota: non esiste un elenco di server globali automatici; se si desidera connettersi a qualcuno tramite IP, è necessario chiedere all'host il proprio IP.
|
join.info = Qui è possibile inserire un [accent]IP del server[] a cui connettersi, o scoprire [accento]un server sulla rete locale[] disponibile.\n Sono supportati sia il multiplayer LAN che WAN. \n\n[LIGHT_GRAY]Nota: non esiste un elenco di server globali automatici; se si desidera connettersi a qualcuno tramite IP, è necessario chiedere all'host il proprio IP.
|
||||||
hostserver = Host Server
|
hostserver = Host Server
|
||||||
hostserver.mobile = Host\nGame
|
hostserver.mobile = Host\nServer
|
||||||
host = Host
|
host = Host
|
||||||
hosting = [accent] Apertura del server ...
|
hosting = [accent] Apertura del server ...
|
||||||
hosts.refresh = Aggiorna
|
hosts.refresh = Aggiorna
|
||||||
@@ -82,7 +82,7 @@ hosts.discovering = Ricerca partite LAN
|
|||||||
server.refreshing = Aggiornamento del server
|
server.refreshing = Aggiornamento del server
|
||||||
hosts.none = [lightgray]Nessuna partita LAN trovata!
|
hosts.none = [lightgray]Nessuna partita LAN trovata!
|
||||||
host.invalid = [scarlet]Impossibile connettersi all'host.
|
host.invalid = [scarlet]Impossibile connettersi all'host.
|
||||||
trace = Trace Player
|
trace = Traccia giocatore
|
||||||
trace.playername = Nome del giocatore: [accent]{0}
|
trace.playername = Nome del giocatore: [accent]{0}
|
||||||
trace.ip = IP: [accent]{0}
|
trace.ip = IP: [accent]{0}
|
||||||
trace.id = ID univoco: [accent]{0}
|
trace.id = ID univoco: [accent]{0}
|
||||||
@@ -185,8 +185,8 @@ builtin = Incluso
|
|||||||
map.delete.confirm = Sei sicuro di voler eliminare questa mappa? Non potrai tornare indietro!
|
map.delete.confirm = Sei sicuro di voler eliminare questa mappa? Non potrai tornare indietro!
|
||||||
map.random = [accent]Mappa casuale
|
map.random = [accent]Mappa casuale
|
||||||
map.nospawn = Questa mappa non possiede un nucleo dove spawnare! Aggiungine uno nell'editor.
|
map.nospawn = Questa mappa non possiede un nucleo dove spawnare! Aggiungine uno nell'editor.
|
||||||
map.nospawn.pvp = This map does not have any enemy cores for player to spawn into! Add[SCARLET] red[] cores to this map in the editor.
|
map.nospawn.pvp = Questa mappa non ha un nucleo nemico! Aggiungi un [SCARLET]nucleo rosso[] nell'editor per poter giocare.
|
||||||
map.nospawn.attack = This map does not have any enemy cores for player to attack! Add[SCARLET] red[] cores to this map in the editor.
|
map.nospawn.attack = Questa mappa non ha un nucleo nemico! Aggiungi un [SCARLET]nucleo rosso[] nell'editor per poter giocare.
|
||||||
map.invalid = Errore nel caricamento della mappa: file mappa corrotto o non valido.
|
map.invalid = Errore nel caricamento della mappa: file mappa corrotto o non valido.
|
||||||
editor.brush = Pennello
|
editor.brush = Pennello
|
||||||
editor.openin = Apri nell'editor
|
editor.openin = Apri nell'editor
|
||||||
@@ -195,32 +195,32 @@ editor.oregen.info = Generazione dei minerali:
|
|||||||
editor.mapinfo = Informazioni mappa
|
editor.mapinfo = Informazioni mappa
|
||||||
editor.author = Autore:
|
editor.author = Autore:
|
||||||
editor.description = Descrizione:
|
editor.description = Descrizione:
|
||||||
editor.waves = Waves:
|
editor.waves = Ondate:
|
||||||
waves.title = Waves
|
waves.title = Ondate
|
||||||
waves.remove = Remove
|
waves.remove = Rimuovi
|
||||||
waves.never = <never>
|
waves.never = <mai>
|
||||||
waves.every = every
|
waves.every = sempre
|
||||||
waves.waves = wave(s)
|
waves.waves = ondata/e
|
||||||
waves.perspawn = per spawn
|
waves.perspawn = per spawn
|
||||||
waves.to = to
|
waves.to = a
|
||||||
waves.boss = Boss
|
waves.boss = Boss
|
||||||
waves.preview = Preview
|
waves.preview = Anteprima
|
||||||
waves.edit = Edit...
|
waves.edit = Modifica...
|
||||||
waves.copy = Copy to Clipboard
|
waves.copy = Copia negli appunti
|
||||||
waves.load = Load from Clipboard
|
waves.load = Caica dagli appunti
|
||||||
waves.invalid = Invalid waves in clipboard.
|
waves.invalid = Onde dagli appunti non valide.
|
||||||
waves.copied = Waves copied.
|
waves.copied = Onde copiate.
|
||||||
editor.default = [LIGHT_GRAY]<Default>
|
editor.default = [LIGHT_GRAY]<Predefinito>
|
||||||
edit = Edit...
|
edit = Modifica...
|
||||||
editor.name = Nome:
|
editor.name = Nome:
|
||||||
editor.teams = Squadre
|
editor.teams = Squadre
|
||||||
editor.elevation = Elevazione
|
editor.elevation = Elevazione
|
||||||
editor.errorload = Error loading file:\n[accent]{0}
|
editor.errorload = Errore nel caricamento di:\n[accent]{0}
|
||||||
editor.errorsave = Error saving file:\n[accent]{0}
|
editor.errorsave = Errore nel salvataggio di:\n[accent]{0}
|
||||||
editor.errorname = Map has no name defined.
|
editor.errorname = Questa mappa è senza nome.
|
||||||
editor.update = Update
|
editor.update = Aggiorna
|
||||||
editor.randomize = Randomize
|
editor.randomize = Casualizza
|
||||||
editor.apply = Apply
|
editor.apply = Applica
|
||||||
editor.generate = Genera
|
editor.generate = Genera
|
||||||
editor.resize = Ridimensiona
|
editor.resize = Ridimensiona
|
||||||
editor.loadmap = Carica\nmappa
|
editor.loadmap = Carica\nmappa
|
||||||
@@ -250,15 +250,15 @@ editor.overwrite = [Accent]Attenzione!\nQuesto sovrascrive una mappa esistente.
|
|||||||
editor.overwrite.confirm = [scarlet]Attenzione![] Una mappa con questo nome esiste già. Sei sicuro di volerla sovrascrivere?
|
editor.overwrite.confirm = [scarlet]Attenzione![] Una mappa con questo nome esiste già. Sei sicuro di volerla sovrascrivere?
|
||||||
editor.selectmap = Seleziona una mappa da caricare:
|
editor.selectmap = Seleziona una mappa da caricare:
|
||||||
filters.empty = [LIGHT_GRAY]No filters! Add one with the button below.
|
filters.empty = [LIGHT_GRAY]No filters! Add one with the button below.
|
||||||
filter.distort = Distort
|
filter.distort = Modifica
|
||||||
filter.noise = Noise
|
filter.noise = Interferenza
|
||||||
filter.ore = Ore
|
filter.ore = Minerali
|
||||||
filter.rivernoise = River Noise
|
filter.rivernoise = Interferenze a fiume
|
||||||
filter.scatter = Scatter
|
filter.scatter = Dispersione
|
||||||
filter.terrain = Terrain
|
filter.terrain = Terreno
|
||||||
filter.option.scale = Scale
|
filter.option.scale = Scala
|
||||||
filter.option.chance = Chance
|
filter.option.chance = Probabilità
|
||||||
filter.option.mag = Magnitude
|
filter.option.mag = Magnitudine
|
||||||
filter.option.threshold = Threshold
|
filter.option.threshold = Threshold
|
||||||
filter.option.circle-scale = Circle Scale
|
filter.option.circle-scale = Circle Scale
|
||||||
filter.option.octaves = Octaves
|
filter.option.octaves = Octaves
|
||||||
|
|||||||
BIN
core/assets/maps/craters.msav
Normal file
BIN
core/assets/maps/desolateRift.msav
Normal file
BIN
core/assets/maps/fortress.msav
Normal file
BIN
core/assets/maps/frozenForest.msav
Normal file
BIN
core/assets/maps/groundZero.msav
Normal file
BIN
core/assets/maps/map_9.msav
Normal file
BIN
core/assets/maps/nuclearProductionComplex.msav
Normal file
BIN
core/assets/maps/overgrowth.msav
Normal file
BIN
core/assets/maps/ruinousShores.msav
Normal file
BIN
core/assets/maps/stainedMountains.msav
Normal file
BIN
core/assets/maps/tarFields.msav
Normal file
|
Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 702 B |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
Before Width: | Height: | Size: 404 KiB After Width: | Height: | Size: 405 KiB |
|
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 307 KiB |
|
Before Width: | Height: | Size: 373 KiB After Width: | Height: | Size: 417 KiB |
@@ -25,6 +25,8 @@ import java.util.Locale;
|
|||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public class Vars{
|
public class Vars{
|
||||||
|
/** Whether to load locales.*/
|
||||||
|
public static boolean loadLocales = true;
|
||||||
/** IO buffer size. */
|
/** IO buffer size. */
|
||||||
public static final int bufferSize = 8192;
|
public static final int bufferSize = 8192;
|
||||||
/** global charset */
|
/** global charset */
|
||||||
@@ -38,9 +40,10 @@ public class Vars{
|
|||||||
/** URL for Github API for releases */
|
/** URL for Github API for releases */
|
||||||
public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases";
|
public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases";
|
||||||
/** URL for Github API for contributors */
|
/** URL for Github API for contributors */
|
||||||
|
//TODO remove and replace with a manually updated list
|
||||||
public static final String contributorsURL = "https://api.github.com/repos/Anuken/Mindustry/contributors";
|
public static final String contributorsURL = "https://api.github.com/repos/Anuken/Mindustry/contributors";
|
||||||
/** URL for sending crash reports to */
|
/** URL for sending crash reports to */
|
||||||
public static final String crashReportURL = "http://mindustry.us.to/report";
|
public static final String crashReportURL = "http://mins.us.to/report";
|
||||||
/** maximum distance between mine and core that supports automatic transferring */
|
/** maximum distance between mine and core that supports automatic transferring */
|
||||||
public static final float mineTransferRange = 220f;
|
public static final float mineTransferRange = 220f;
|
||||||
/** team of the player by default */
|
/** team of the player by default */
|
||||||
@@ -104,8 +107,10 @@ public class Vars{
|
|||||||
public static FileHandle customMapDirectory;
|
public static FileHandle customMapDirectory;
|
||||||
/** data subdirectory used for saves */
|
/** data subdirectory used for saves */
|
||||||
public static FileHandle saveDirectory;
|
public static FileHandle saveDirectory;
|
||||||
|
/** old map file extension, for conversion */
|
||||||
|
public static final String oldMapExtension = "mmap";
|
||||||
/** map file extension */
|
/** map file extension */
|
||||||
public static final String mapExtension = "mmap";
|
public static final String mapExtension = "msav";
|
||||||
/** save file extension */
|
/** save file extension */
|
||||||
public static final String saveExtension = "msav";
|
public static final String saveExtension = "msav";
|
||||||
|
|
||||||
@@ -141,19 +146,22 @@ public class Vars{
|
|||||||
public static void init(){
|
public static void init(){
|
||||||
Serialization.init();
|
Serialization.init();
|
||||||
|
|
||||||
//load locales
|
if(loadLocales){
|
||||||
String[] stra = Core.files.internal("locales").readString().split("\n");
|
//load locales
|
||||||
locales = new Locale[stra.length];
|
String[] stra = Core.files.internal("locales").readString().split("\n");
|
||||||
for(int i = 0; i < locales.length; i++){
|
locales = new Locale[stra.length];
|
||||||
String code = stra[i];
|
for(int i = 0; i < locales.length; i++){
|
||||||
if(code.contains("_")){
|
String code = stra[i];
|
||||||
locales[i] = new Locale(code.split("_")[0], code.split("_")[1]);
|
if(code.contains("_")){
|
||||||
}else{
|
locales[i] = new Locale(code.split("_")[0], code.split("_")[1]);
|
||||||
locales[i] = new Locale(code);
|
}else{
|
||||||
|
locales[i] = new Locale(code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Arrays.sort(locales, Structs.comparing(l -> l.getDisplayName(l), String.CASE_INSENSITIVE_ORDER));
|
||||||
}
|
}
|
||||||
|
|
||||||
Arrays.sort(locales, Structs.comparing(l -> l.getDisplayName(l), String.CASE_INSENSITIVE_ORDER));
|
|
||||||
Version.init();
|
Version.init();
|
||||||
|
|
||||||
content = new ContentLoader();
|
content = new ContentLoader();
|
||||||
|
|||||||
@@ -171,12 +171,10 @@ public class BlockIndexer{
|
|||||||
|
|
||||||
for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx++){
|
for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx++){
|
||||||
for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty++){
|
for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty++){
|
||||||
Tile other = world.tile(tx, ty);
|
Tile other = world.ltile(tx, ty);
|
||||||
|
|
||||||
if(other == null) continue;
|
if(other == null) continue;
|
||||||
|
|
||||||
other = other.target();
|
|
||||||
|
|
||||||
if(other.entity == null || other.getTeam() != team || !pred.test(other) || !other.block().targetable)
|
if(other.entity == null || other.getTeam() != team || !pred.test(other) || !other.block().targetable)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -293,7 +291,7 @@ public class BlockIndexer{
|
|||||||
outer:
|
outer:
|
||||||
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
|
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
|
||||||
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
|
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
|
||||||
Tile result = world.tile(x, y).target();
|
Tile result = world.ltile(x, y);
|
||||||
//when a targetable block is found, mark this quadrant as occupied and stop searching
|
//when a targetable block is found, mark this quadrant as occupied and stop searching
|
||||||
if(result.entity != null && result.getTeam() == data.team){
|
if(result.entity != null && result.getTeam() == data.team){
|
||||||
structQuadrants[data.team.ordinal()].set(index);
|
structQuadrants[data.team.ordinal()].set(index);
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ public class Pathfinder{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean passable(Tile tile, Team team){
|
private boolean passable(Tile tile, Team team){
|
||||||
return (!tile.solid()) || (tile.breakable() && (tile.target().getTeam() != team));
|
return (!tile.solid()) || (tile.breakable() && (tile.getTeam() != team));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package io.anuke.mindustry.ai;
|
|||||||
|
|
||||||
import io.anuke.arc.Events;
|
import io.anuke.arc.Events;
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
import io.anuke.arc.collection.IntArray;
|
|
||||||
import io.anuke.arc.math.Angles;
|
import io.anuke.arc.math.Angles;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.Time;
|
||||||
|
import io.anuke.arc.util.Tmp;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.content.Fx;
|
import io.anuke.mindustry.content.Fx;
|
||||||
import io.anuke.mindustry.entities.Damage;
|
import io.anuke.mindustry.entities.Damage;
|
||||||
@@ -14,48 +14,25 @@ import io.anuke.mindustry.entities.type.BaseUnit;
|
|||||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||||
import io.anuke.mindustry.game.SpawnGroup;
|
import io.anuke.mindustry.game.SpawnGroup;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
import io.anuke.mindustry.world.Pos;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class WaveSpawner{
|
public class WaveSpawner{
|
||||||
private Array<FlyerSpawn> flySpawns = new Array<>();
|
private Array<FlyerSpawn> flySpawns = new Array<>();
|
||||||
private Array<GroundSpawn> groundSpawns = new Array<>();
|
private Array<GroundSpawn> groundSpawns = new Array<>();
|
||||||
private IntArray loadedSpawns = new IntArray();
|
|
||||||
private boolean spawning = false;
|
private boolean spawning = false;
|
||||||
|
|
||||||
public WaveSpawner(){
|
public WaveSpawner(){
|
||||||
Events.on(WorldLoadEvent.class, e -> reset());
|
Events.on(WorldLoadEvent.class, e -> reset());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(DataOutput stream) throws IOException{
|
|
||||||
stream.writeInt(groundSpawns.size);
|
|
||||||
for(GroundSpawn spawn : groundSpawns){
|
|
||||||
stream.writeInt(Pos.get(spawn.x, spawn.y));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void read(DataInput stream) throws IOException{
|
|
||||||
flySpawns.clear();
|
|
||||||
groundSpawns.clear();
|
|
||||||
loadedSpawns.clear();
|
|
||||||
|
|
||||||
int amount = stream.readInt();
|
|
||||||
|
|
||||||
for(int i = 0; i < amount; i++){
|
|
||||||
loadedSpawns.add(stream.readInt());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int countSpawns(){
|
public int countSpawns(){
|
||||||
return groundSpawns.size;
|
return groundSpawns.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @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.count(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius) > 0;
|
return groundSpawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void spawnEnemies(){
|
public void spawnEnemies(){
|
||||||
@@ -117,21 +94,11 @@ public class WaveSpawner{
|
|||||||
for(int x = 0; x < world.width(); x++){
|
for(int x = 0; x < world.width(); x++){
|
||||||
for(int y = 0; y < world.height(); y++){
|
for(int y = 0; y < world.height(); y++){
|
||||||
|
|
||||||
if(world.tile(x, y).block() == Blocks.spawn){
|
if(world.tile(x, y).overlay() == Blocks.spawn){
|
||||||
addSpawns(x, y);
|
addSpawns(x, y);
|
||||||
|
|
||||||
//hide spawnpoints, they have served their purpose
|
|
||||||
world.tile(x, y).setBlock(Blocks.air);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < loadedSpawns.size; i++){
|
|
||||||
int pos = loadedSpawns.get(i);
|
|
||||||
addSpawns(Pos.x(pos), Pos.y(pos));
|
|
||||||
}
|
|
||||||
|
|
||||||
loadedSpawns.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSpawns(int x, int y){
|
private void addSpawns(int x, int y){
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ public class Blocks implements ContentList{
|
|||||||
public static Block
|
public static Block
|
||||||
|
|
||||||
//environment
|
//environment
|
||||||
air, part, spawn, deepwater, water, taintedWater, tar, stone, craters, charr, sand, darksand, ice, snow, darksandTaintedWater,
|
air, spawn, deepwater, water, taintedWater, tar, stone, craters, charr, sand, darksand, ice, snow, darksandTaintedWater,
|
||||||
holostone, rocks, sporerocks, icerocks, cliffs, sporePine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
|
holostone, rocks, sporerocks, icerocks, cliffs, sporePine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
|
||||||
iceSnow, sandWater, darksandWater, duneRocks, sandRocks, moss, sporeMoss, shale, shaleRocks, shaleBoulder, grass, salt,
|
iceSnow, sandWater, darksandWater, duneRocks, sandRocks, moss, sporeMoss, shale, shaleRocks, shaleBoulder, grass, salt,
|
||||||
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, ignarock, magmarock, hotrock, snowrocks, rock, snowrock, saltRocks,
|
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, ignarock, magmarock, hotrock, snowrocks, rock, snowrock, saltRocks,
|
||||||
@@ -88,15 +88,9 @@ public class Blocks implements ContentList{
|
|||||||
hasShadow = false;
|
hasShadow = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(Tile tile){
|
public void draw(Tile tile){}
|
||||||
}
|
public void load(){}
|
||||||
|
public void init(){}
|
||||||
public void load(){
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init(){
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isHidden(){
|
public boolean isHidden(){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -109,14 +103,24 @@ public class Blocks implements ContentList{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
part = new BlockPart();
|
//create special blockpart variants
|
||||||
|
for(int dx = 0; dx < BlockPart.maxSize; dx++){
|
||||||
|
for(int dy = 0; dy < BlockPart.maxSize; dy++){
|
||||||
|
int fx = dx - BlockPart.maxSize/2, fy = dy - BlockPart.maxSize/2;
|
||||||
|
if(fx != 0 || fy != 0){
|
||||||
|
new BlockPart(fx, fy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spawn = new Block("spawn");
|
spawn = new OverlayFloor("spawn"){
|
||||||
|
public void draw(Tile tile){}
|
||||||
|
};
|
||||||
|
|
||||||
//Registers build blocks from size 1-6
|
//Registers build blocks
|
||||||
//no reference is needed here since they can be looked up by name later
|
//no reference is needed here since they can be looked up by name later
|
||||||
for(int i = 1; i <= 6; i++){
|
for(int i = 1; i <= BuildBlock.maxSize; i++){
|
||||||
new BuildBlock("build" + i);
|
new BuildBlock(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
deepwater = new Floor("deepwater"){{
|
deepwater = new Floor("deepwater"){{
|
||||||
@@ -556,7 +560,7 @@ public class Blocks implements ContentList{
|
|||||||
drawer = tile -> {
|
drawer = tile -> {
|
||||||
LiquidModule mod = tile.entity.liquids;
|
LiquidModule mod = tile.entity.liquids;
|
||||||
|
|
||||||
int rotation = rotate ? tile.getRotation() * 90 : 0;
|
int rotation = rotate ? tile.rotation() * 90 : 0;
|
||||||
|
|
||||||
Draw.rect(reg(bottomRegion), tile.drawx(), tile.drawy(), rotation);
|
Draw.rect(reg(bottomRegion), tile.drawx(), tile.drawy(), rotation);
|
||||||
|
|
||||||
@@ -1105,11 +1109,11 @@ public class Blocks implements ContentList{
|
|||||||
requirements(Category.power, ItemStack.with(Items.lead, 1000, Items.silicon, 600, Items.graphite, 800, Items.thorium, 200, Items.surgealloy, 500, Items.metaglass, 500));
|
requirements(Category.power, ItemStack.with(Items.lead, 1000, Items.silicon, 600, Items.graphite, 800, Items.thorium, 200, Items.surgealloy, 500, Items.metaglass, 500));
|
||||||
size = 4;
|
size = 4;
|
||||||
health = 900;
|
health = 900;
|
||||||
powerProduction = 110f;
|
powerProduction = 130f;
|
||||||
itemDuration = 60f;
|
itemDuration = 90f;
|
||||||
consumes.power(25f);
|
consumes.power(25f);
|
||||||
consumes.item(Items.blastCompound);
|
consumes.item(Items.blastCompound);
|
||||||
consumes.liquid(Liquids.cryofluid, 0.26f);
|
consumes.liquid(Liquids.cryofluid, 0.25f);
|
||||||
}};
|
}};
|
||||||
|
|
||||||
//endregion power
|
//endregion power
|
||||||
@@ -1147,7 +1151,7 @@ public class Blocks implements ContentList{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
blastDrill = new Drill("blast-drill"){{
|
blastDrill = new Drill("blast-drill"){{
|
||||||
requirements(Category.production, ItemStack.with(Items.copper, 130, Items.silicon, 120, Items.titanium, 100, Items.thorium, 60));
|
requirements(Category.production, ItemStack.with(Items.copper, 130, Items.silicon, 120, Items.titanium, 100, Items.thorium, 100));
|
||||||
drillTime = 200;
|
drillTime = 200;
|
||||||
size = 4;
|
size = 4;
|
||||||
drawRim = true;
|
drawRim = true;
|
||||||
|
|||||||
@@ -398,9 +398,9 @@ public class Bullets implements ContentList{
|
|||||||
@Override
|
@Override
|
||||||
public void hitTile(Bullet b, Tile tile){
|
public void hitTile(Bullet b, Tile tile){
|
||||||
super.hit(b);
|
super.hit(b);
|
||||||
tile = tile.target();
|
tile = tile.link();
|
||||||
|
|
||||||
if(tile != null && tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){
|
if(tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){
|
||||||
Effects.effect(Fx.healBlockFull, Pal.heal, tile.drawx(), tile.drawy(), tile.block().size);
|
Effects.effect(Fx.healBlockFull, Pal.heal, tile.drawx(), tile.drawy(), tile.block().size);
|
||||||
tile.entity.healBy(healPercent / 100f * tile.entity.maxHealth());
|
tile.entity.healBy(healPercent / 100f * tile.entity.maxHealth());
|
||||||
}
|
}
|
||||||
@@ -424,7 +424,6 @@ public class Bullets implements ContentList{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(Bullet b){
|
public void draw(Bullet b){
|
||||||
//TODO add color to the bullet depending on the color of the flame it came from
|
|
||||||
Draw.color(Pal.lightFlame, Pal.darkFlame, Color.GRAY, b.fin());
|
Draw.color(Pal.lightFlame, Pal.darkFlame, Color.GRAY, b.fin());
|
||||||
Fill.circle(b.x, b.y, 3f * b.fout());
|
Fill.circle(b.x, b.y, 3f * b.fout());
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.anuke.arc.math.Mathf;
|
|||||||
import io.anuke.arc.util.Time;
|
import io.anuke.arc.util.Time;
|
||||||
import io.anuke.mindustry.entities.Effects;
|
import io.anuke.mindustry.entities.Effects;
|
||||||
import io.anuke.mindustry.entities.Units;
|
import io.anuke.mindustry.entities.Units;
|
||||||
|
import io.anuke.mindustry.entities.bullet.BombBulletType;
|
||||||
import io.anuke.mindustry.entities.effect.Lightning;
|
import io.anuke.mindustry.entities.effect.Lightning;
|
||||||
import io.anuke.mindustry.entities.type.Player;
|
import io.anuke.mindustry.entities.type.Player;
|
||||||
import io.anuke.mindustry.game.ContentList;
|
import io.anuke.mindustry.game.ContentList;
|
||||||
@@ -307,11 +308,11 @@ public class Mechs implements ContentList{
|
|||||||
trident = new Mech("trident-ship", true){
|
trident = new Mech("trident-ship", true){
|
||||||
{
|
{
|
||||||
drillPower = 2;
|
drillPower = 2;
|
||||||
speed = 0.14f;
|
speed = 0.15f;
|
||||||
drag = 0.034f;
|
drag = 0.034f;
|
||||||
mass = 2.5f;
|
mass = 2.5f;
|
||||||
turnCursor = false;
|
turnCursor = false;
|
||||||
health = 220f;
|
health = 250f;
|
||||||
itemCapacity = 30;
|
itemCapacity = 30;
|
||||||
engineColor = Color.valueOf("84f491");
|
engineColor = Color.valueOf("84f491");
|
||||||
cellTrnsY = 1f;
|
cellTrnsY = 1f;
|
||||||
@@ -319,14 +320,22 @@ public class Mechs implements ContentList{
|
|||||||
weapon = new Weapon("bomber"){{
|
weapon = new Weapon("bomber"){{
|
||||||
length = 0f;
|
length = 0f;
|
||||||
width = 2f;
|
width = 2f;
|
||||||
reload = 8f;
|
reload = 25f;
|
||||||
shots = 2;
|
shots = 2;
|
||||||
|
shotDelay = 1f;
|
||||||
|
shots = 8;
|
||||||
roundrobin = true;
|
roundrobin = true;
|
||||||
ejectEffect = Fx.none;
|
ejectEffect = Fx.none;
|
||||||
velocityRnd = 1f;
|
velocityRnd = 1f;
|
||||||
inaccuracy = 40f;
|
inaccuracy = 20f;
|
||||||
ignoreRotation = true;
|
ignoreRotation = true;
|
||||||
bullet = Bullets.bombExplosive;
|
bullet = new BombBulletType(14f, 25f, "shell"){{
|
||||||
|
bulletWidth = 10f;
|
||||||
|
bulletHeight = 14f;
|
||||||
|
hitEffect = Fx.flakExplosion;
|
||||||
|
shootEffect = Fx.none;
|
||||||
|
smokeEffect = Fx.none;
|
||||||
|
}};
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,8 +75,6 @@ public class StatusEffects implements ContentList{
|
|||||||
armorMultiplier = 3f;
|
armorMultiplier = 3f;
|
||||||
damageMultiplier = 3f;
|
damageMultiplier = 3f;
|
||||||
speedMultiplier = 1.1f;
|
speedMultiplier = 1.1f;
|
||||||
//TODO custom effect
|
|
||||||
//effect = Fx.overdriven;
|
|
||||||
}};
|
}};
|
||||||
|
|
||||||
shocked = new StatusEffect();
|
shocked = new StatusEffect();
|
||||||
|
|||||||
@@ -154,20 +154,6 @@ public class Zones implements ContentList{
|
|||||||
}};
|
}};
|
||||||
}};
|
}};
|
||||||
|
|
||||||
/*
|
|
||||||
crags = new Zone("crags", new MapGenerator("groundZero", 1)){{ //TODO implement
|
|
||||||
baseLaunchCost = ItemStack.with(Items.copper, 300);
|
|
||||||
startingItems = ItemStack.with(Items.copper, 200);
|
|
||||||
conditionWave = 15;
|
|
||||||
zoneRequirements = new Zone[]{frozenForest};
|
|
||||||
blockRequirements = new Block[]{Blocks.copperWall};
|
|
||||||
rules = () -> new Rules(){{
|
|
||||||
waves = true;]
|
|
||||||
waveTimer = true;
|
|
||||||
waveSpacing = 60 * 80;
|
|
||||||
}};
|
|
||||||
}};*/
|
|
||||||
|
|
||||||
stainedMountains = new Zone("stainedMountains", new MapGenerator("stainedMountains", 2)
|
stainedMountains = new Zone("stainedMountains", new MapGenerator("stainedMountains", 2)
|
||||||
.dist(0f, false)
|
.dist(0f, false)
|
||||||
.decor(new Decoration(Blocks.shale, Blocks.shaleBoulder, 0.02))){{
|
.decor(new Decoration(Blocks.shale, Blocks.shaleBoulder, 0.02))){{
|
||||||
|
|||||||
@@ -90,17 +90,12 @@ public class ContentLoader{
|
|||||||
for(Array<Content> arr : contentMap){
|
for(Array<Content> arr : contentMap){
|
||||||
for(int i = 0; i < arr.size; i++){
|
for(int i = 0; i < arr.size; i++){
|
||||||
int id = arr.get(i).id;
|
int id = arr.get(i).id;
|
||||||
if(id < 0) id += 256;
|
|
||||||
if(id != i){
|
if(id != i){
|
||||||
throw new IllegalArgumentException("Out-of-order IDs for content '" + arr.get(i) + "' (expected " + i + " but got " + id + ")");
|
throw new IllegalArgumentException("Out-of-order IDs for content '" + arr.get(i) + "' (expected " + i + " but got " + id + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(blocks().size >= 256){
|
|
||||||
throw new ImpendingDoomException("THE TIME HAS COME. More than 256 blocks have been created.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(verbose){
|
if(verbose){
|
||||||
Log.info("--- CONTENT INFO ---");
|
Log.info("--- CONTENT INFO ---");
|
||||||
for(int k = 0; k < contentMap.length; k++){
|
for(int k = 0; k < contentMap.length; k++){
|
||||||
@@ -129,7 +124,7 @@ public class ContentLoader{
|
|||||||
/** Loads block colors. */
|
/** Loads block colors. */
|
||||||
public void loadColors(){
|
public void loadColors(){
|
||||||
Pixmap pixmap = new Pixmap(files.internal("sprites/block_colors.png"));
|
Pixmap pixmap = new Pixmap(files.internal("sprites/block_colors.png"));
|
||||||
for(int i = 0; i < 256; i++){
|
for(int i = 0; i < pixmap.getWidth(); i++){
|
||||||
if(blocks().size > i){
|
if(blocks().size > i){
|
||||||
int color = pixmap.getPixel(i, 0);
|
int color = pixmap.getPixel(i, 0);
|
||||||
|
|
||||||
@@ -170,10 +165,12 @@ public class ContentLoader{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public <T extends Content> T getByID(ContentType type, int id){
|
public <T extends Content> T getByID(ContentType type, int id){
|
||||||
//offset negative values by 256, as they are probably a product of byte overflow
|
|
||||||
if(id < 0) id += 256;
|
|
||||||
|
|
||||||
if(temporaryMapper != null && temporaryMapper[type.ordinal()] != null && temporaryMapper[type.ordinal()].length != 0){
|
if(temporaryMapper != null && temporaryMapper[type.ordinal()] != null && temporaryMapper[type.ordinal()].length != 0){
|
||||||
|
//-1 = invalid content
|
||||||
|
if(id < 0){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
if(temporaryMapper[type.ordinal()].length <= id || temporaryMapper[type.ordinal()][id] == null){
|
if(temporaryMapper[type.ordinal()].length <= id || temporaryMapper[type.ordinal()][id] == null){
|
||||||
return getByID(type, 0); //default value is always ID 0
|
return getByID(type, 0); //default value is always ID 0
|
||||||
}
|
}
|
||||||
@@ -243,10 +240,4 @@ public class ContentLoader{
|
|||||||
TypeTrait.registerType(Bullet.class, Bullet::new);
|
TypeTrait.registerType(Bullet.class, Bullet::new);
|
||||||
TypeTrait.registerType(Lightning.class, Lightning::new);
|
TypeTrait.registerType(Lightning.class, Lightning::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ImpendingDoomException extends RuntimeException{
|
|
||||||
ImpendingDoomException(String s){
|
|
||||||
super(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import io.anuke.mindustry.gen.Call;
|
|||||||
import io.anuke.mindustry.input.*;
|
import io.anuke.mindustry.input.*;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.*;
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ public class Control implements ApplicationListener{
|
|||||||
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
|
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
|
||||||
//the restart dialog can show info for any number of scenarios
|
//the restart dialog can show info for any number of scenarios
|
||||||
Call.onGameOver(event.winner);
|
Call.onGameOver(event.winner);
|
||||||
if(state.rules.zone != -1){
|
if(state.rules.zone != null){
|
||||||
//remove zone save on game over
|
//remove zone save on game over
|
||||||
if(saves.getZoneSlot() != null){
|
if(saves.getZoneSlot() != null){
|
||||||
saves.getZoneSlot().delete();
|
saves.getZoneSlot().delete();
|
||||||
@@ -201,8 +201,25 @@ public class Control implements ApplicationListener{
|
|||||||
public void playMap(Map map, Rules rules){
|
public void playMap(Map map, Rules rules){
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
logic.reset();
|
logic.reset();
|
||||||
state.rules = rules;
|
|
||||||
world.loadMap(map);
|
world.loadMap(map);
|
||||||
|
state.rules = rules;
|
||||||
|
logic.play();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void playZone(Zone zone){
|
||||||
|
ui.loadAnd(() -> {
|
||||||
|
logic.reset();
|
||||||
|
world.loadGenerator(zone.generator);
|
||||||
|
state.rules = zone.rules.get();
|
||||||
|
state.rules.zone = zone;
|
||||||
|
for(Tile core : state.teams.get(defaultTeam).cores){
|
||||||
|
for(ItemStack stack : zone.getStartingItems()){
|
||||||
|
core.entity.items.add(stack.item, stack.amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.set(State.playing);
|
||||||
|
control.saves.zoneSave();
|
||||||
logic.play();
|
logic.play();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ public class GameState{
|
|||||||
state = astate;
|
state = astate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEditor(){
|
||||||
|
return rules.editor;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isPaused(){
|
public boolean isPaused(){
|
||||||
return (is(State.paused) && !Net.active()) || (gameOver && !Net.active());
|
return (is(State.paused) && !Net.active()) || (gameOver && !Net.active());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,12 +58,6 @@ public class Logic implements ApplicationListener{
|
|||||||
public void play(){
|
public void play(){
|
||||||
state.set(State.playing);
|
state.set(State.playing);
|
||||||
state.wavetime = state.rules.waveSpacing * 2; //grace period of 2x wave time before game starts
|
state.wavetime = state.rules.waveSpacing * 2; //grace period of 2x wave time before game starts
|
||||||
|
|
||||||
//sometimes a map has no waves defined, they're defined in the zone rules
|
|
||||||
if(world.getMap().getWaves() != DefaultWaves.get() || !world.isZone()){
|
|
||||||
state.rules.spawns = world.getMap().getWaves();
|
|
||||||
}
|
|
||||||
|
|
||||||
Events.fire(new PlayEvent());
|
Events.fire(new PlayEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +86,7 @@ public class Logic implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkGameOver(){
|
private void checkGameOver(){
|
||||||
if(state.rules.waves && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){
|
if(!state.rules.attackMode && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){
|
||||||
state.gameOver = true;
|
state.gameOver = true;
|
||||||
Events.fire(new GameOverEvent(waveTeam));
|
Events.fire(new GameOverEvent(waveTeam));
|
||||||
}else if(state.rules.attackMode){
|
}else if(state.rules.attackMode){
|
||||||
@@ -165,15 +159,17 @@ public class Logic implements ApplicationListener{
|
|||||||
Entities.update(groundEffectGroup);
|
Entities.update(groundEffectGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(EntityGroup group : unitGroups){
|
if(!state.isEditor()){
|
||||||
Entities.update(group);
|
for(EntityGroup group : unitGroups){
|
||||||
}
|
Entities.update(group);
|
||||||
|
}
|
||||||
|
|
||||||
Entities.update(puddleGroup);
|
Entities.update(puddleGroup);
|
||||||
Entities.update(shieldGroup);
|
Entities.update(shieldGroup);
|
||||||
Entities.update(bulletGroup);
|
Entities.update(bulletGroup);
|
||||||
Entities.update(tileGroup);
|
Entities.update(tileGroup);
|
||||||
Entities.update(fireGroup);
|
Entities.update(fireGroup);
|
||||||
|
}
|
||||||
Entities.update(playerGroup);
|
Entities.update(playerGroup);
|
||||||
|
|
||||||
//effect group only contains item transfers in the headless version, update it!
|
//effect group only contains item transfers in the headless version, update it!
|
||||||
@@ -181,19 +177,21 @@ public class Logic implements ApplicationListener{
|
|||||||
Entities.update(effectGroup);
|
Entities.update(effectGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(EntityGroup group : unitGroups){
|
if(!state.isEditor()){
|
||||||
if(group.isEmpty()) continue;
|
|
||||||
|
|
||||||
collisions.collideGroups(bulletGroup, group);
|
for(EntityGroup group : unitGroups){
|
||||||
|
if(group.isEmpty()) continue;
|
||||||
|
collisions.collideGroups(bulletGroup, group);
|
||||||
|
}
|
||||||
|
|
||||||
|
collisions.collideGroups(bulletGroup, playerGroup);
|
||||||
|
collisions.collideGroups(playerGroup, playerGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
collisions.collideGroups(bulletGroup, playerGroup);
|
|
||||||
collisions.collideGroups(playerGroup, playerGroup);
|
|
||||||
|
|
||||||
world.pathfinder.update();
|
world.pathfinder.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Net.client() && !world.isInvalidMap()){
|
if(!Net.client() && !world.isInvalidMap() && !state.isEditor()){
|
||||||
checkGameOver();
|
checkGameOver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import io.anuke.mindustry.entities.type.Player;
|
|||||||
import io.anuke.mindustry.game.Version;
|
import io.anuke.mindustry.game.Version;
|
||||||
import io.anuke.mindustry.gen.Call;
|
import io.anuke.mindustry.gen.Call;
|
||||||
import io.anuke.mindustry.gen.RemoteReadClient;
|
import io.anuke.mindustry.gen.RemoteReadClient;
|
||||||
|
import io.anuke.mindustry.net.Administration.TraceInfo;
|
||||||
import io.anuke.mindustry.net.*;
|
import io.anuke.mindustry.net.*;
|
||||||
import io.anuke.mindustry.net.Net.SendMode;
|
import io.anuke.mindustry.net.Net.SendMode;
|
||||||
import io.anuke.mindustry.net.Packets.*;
|
import io.anuke.mindustry.net.Packets.*;
|
||||||
@@ -117,7 +118,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//called on all clients
|
//called on all clients
|
||||||
@Remote(called = Loc.server, targets = Loc.server)
|
@Remote(called = Loc.server, targets = Loc.server, variants = Variant.both)
|
||||||
public static void sendMessage(String message, String sender, Player playersender){
|
public static void sendMessage(String message, String sender, Player playersender){
|
||||||
if(Vars.ui != null){
|
if(Vars.ui != null){
|
||||||
Vars.ui.chatfrag.addMessage(message, sender);
|
Vars.ui.chatfrag.addMessage(message, sender);
|
||||||
@@ -158,6 +159,13 @@ public class NetClient implements ApplicationListener{
|
|||||||
return "[#" + player.color.toString().toUpperCase() + "]" + name;
|
return "[#" + player.color.toString().toUpperCase() + "]" + name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Remote(variants = Variant.one)
|
||||||
|
public static void onTraceInfo(Player player, TraceInfo info){
|
||||||
|
if(player != null){
|
||||||
|
ui.traces.show(player, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Remote(variants = Variant.one, priority = PacketPriority.high)
|
@Remote(variants = Variant.one, priority = PacketPriority.high)
|
||||||
public static void onKick(KickReason reason){
|
public static void onKick(KickReason reason){
|
||||||
netClient.disconnectQuietly();
|
netClient.disconnectQuietly();
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ import io.anuke.arc.math.Mathf;
|
|||||||
import io.anuke.arc.math.geom.Rectangle;
|
import io.anuke.arc.math.geom.Rectangle;
|
||||||
import io.anuke.arc.math.geom.Vector2;
|
import io.anuke.arc.math.geom.Vector2;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.io.ByteBufferOutput;
|
import io.anuke.arc.util.io.*;
|
||||||
import io.anuke.arc.util.io.ReusableByteOutStream;
|
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.entities.Entities;
|
import io.anuke.mindustry.entities.Entities;
|
||||||
@@ -29,6 +28,7 @@ import io.anuke.mindustry.gen.Call;
|
|||||||
import io.anuke.mindustry.gen.RemoteReadServer;
|
import io.anuke.mindustry.gen.RemoteReadServer;
|
||||||
import io.anuke.mindustry.net.*;
|
import io.anuke.mindustry.net.*;
|
||||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||||
|
import io.anuke.mindustry.net.Administration.TraceInfo;
|
||||||
import io.anuke.mindustry.net.Packets.*;
|
import io.anuke.mindustry.net.Packets.*;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
|
|
||||||
public void sendWorldData(Player player, int clientID){
|
public void sendWorldData(Player player, int clientID){
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
DeflaterOutputStream def = new DeflaterOutputStream(stream);
|
DeflaterOutputStream def = new FastDeflaterOutputStream(stream);
|
||||||
NetworkIO.writeWorld(player, def);
|
NetworkIO.writeWorld(player, def);
|
||||||
WorldStream data = new WorldStream();
|
WorldStream data = new WorldStream();
|
||||||
data.stream = new ByteArrayInputStream(stream.toByteArray());
|
data.stream = new ByteArrayInputStream(stream.toByteArray());
|
||||||
@@ -289,7 +289,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
//auto-skip done requests
|
//auto-skip done requests
|
||||||
if(req.breaking && tile.block() == Blocks.air){
|
if(req.breaking && tile.block() == Blocks.air){
|
||||||
continue;
|
continue;
|
||||||
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.getRotation() == req.rotation)){
|
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || tile.rotation() == req.rotation)){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
player.getPlaceQueue().addLast(req);
|
player.getPlaceQueue().addLast(req);
|
||||||
@@ -355,11 +355,11 @@ public class NetServer implements ApplicationListener{
|
|||||||
netServer.kick(other.con.id, KickReason.kick);
|
netServer.kick(other.con.id, KickReason.kick);
|
||||||
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
|
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
|
||||||
}else if(action == AdminAction.trace){
|
}else if(action == AdminAction.trace){
|
||||||
//TODO implement
|
TraceInfo info = new TraceInfo(other.con.address, other.uuid, other.con.modclient, other.con.mobile);
|
||||||
if(player.con != null){
|
if(player.con != null){
|
||||||
//Call.onTraceInfo(player.con.id, other.con.trace);
|
Call.onTraceInfo(player.con.id, other, info);
|
||||||
}else{
|
}else{
|
||||||
//NetClient.onTraceInfo(other.con.trace);
|
NetClient.onTraceInfo(other, info);
|
||||||
}
|
}
|
||||||
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
||||||
}
|
}
|
||||||
@@ -478,7 +478,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
|
|
||||||
sent++;
|
sent++;
|
||||||
|
|
||||||
if(syncStream.position() > maxSnapshotSize){
|
if(syncStream.size() > maxSnapshotSize){
|
||||||
dataStream.close();
|
dataStream.close();
|
||||||
byte[] syncBytes = syncStream.toByteArray();
|
byte[] syncBytes = syncStream.toByteArray();
|
||||||
Call.onEntitySnapshot(player.con.id, (byte)group.getID(), (short)sent, (short)syncBytes.length, Net.compressSnapshot(syncBytes));
|
Call.onEntitySnapshot(player.con.id, (byte)group.getID(), (short)sent, (short)syncBytes.length, Net.compressSnapshot(syncBytes));
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package io.anuke.mindustry.core;
|
|||||||
|
|
||||||
import io.anuke.annotations.Annotations.Nullable;
|
import io.anuke.annotations.Annotations.Nullable;
|
||||||
import io.anuke.arc.*;
|
import io.anuke.arc.*;
|
||||||
import io.anuke.arc.collection.Array;
|
|
||||||
import io.anuke.arc.collection.IntArray;
|
import io.anuke.arc.collection.IntArray;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.math.geom.Geometry;
|
import io.anuke.arc.math.geom.Geometry;
|
||||||
@@ -18,8 +17,9 @@ import io.anuke.mindustry.game.Team;
|
|||||||
import io.anuke.mindustry.io.MapIO;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
import io.anuke.mindustry.maps.*;
|
import io.anuke.mindustry.maps.*;
|
||||||
import io.anuke.mindustry.maps.generators.Generator;
|
import io.anuke.mindustry.maps.generators.Generator;
|
||||||
import io.anuke.mindustry.type.*;
|
import io.anuke.mindustry.type.Zone;
|
||||||
import io.anuke.mindustry.world.*;
|
import io.anuke.mindustry.world.*;
|
||||||
|
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
@@ -28,17 +28,22 @@ public class World implements ApplicationListener{
|
|||||||
public final BlockIndexer indexer = new BlockIndexer();
|
public final BlockIndexer indexer = new BlockIndexer();
|
||||||
public final WaveSpawner spawner = new WaveSpawner();
|
public final WaveSpawner spawner = new WaveSpawner();
|
||||||
public final Pathfinder pathfinder = new Pathfinder();
|
public final Pathfinder pathfinder = new Pathfinder();
|
||||||
|
public final Context context = new Context();
|
||||||
|
|
||||||
private Map currentMap;
|
private Map currentMap;
|
||||||
private Tile[][] tiles;
|
private Tile[][] tiles;
|
||||||
|
|
||||||
private Array<Tile> tempTiles = new Array<>();
|
|
||||||
private boolean generating, invalidMap;
|
private boolean generating, invalidMap;
|
||||||
|
|
||||||
public World(){
|
public World(){
|
||||||
maps.load();
|
maps.load();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(){
|
||||||
|
maps.loadLegacyMaps();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void dispose(){
|
public void dispose(){
|
||||||
maps.dispose();
|
maps.dispose();
|
||||||
@@ -97,6 +102,12 @@ public class World implements ApplicationListener{
|
|||||||
return tiles[x][y];
|
return tiles[x][y];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable Tile ltile(int x, int y){
|
||||||
|
Tile tile = tile(x, y);
|
||||||
|
if(tile == null) return null;
|
||||||
|
return tile.block().linked(tile);
|
||||||
|
}
|
||||||
|
|
||||||
public Tile rawTile(int x, int y){
|
public Tile rawTile(int x, int y){
|
||||||
return tiles[x][y];
|
return tiles[x][y];
|
||||||
}
|
}
|
||||||
@@ -105,6 +116,10 @@ public class World implements ApplicationListener{
|
|||||||
return tile(Math.round(x / tilesize), Math.round(y / tilesize));
|
return tile(Math.round(x / tilesize), Math.round(y / tilesize));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable Tile ltileWorld(float x, float y){
|
||||||
|
return ltile(Math.round(x / tilesize), Math.round(y / tilesize));
|
||||||
|
}
|
||||||
|
|
||||||
public int toTile(float coord){
|
public int toTile(float coord){
|
||||||
return Math.round(coord / tilesize);
|
return Math.round(coord / tilesize);
|
||||||
}
|
}
|
||||||
@@ -160,6 +175,8 @@ public class World implements ApplicationListener{
|
|||||||
* A WorldLoadEvent will be fire.
|
* A WorldLoadEvent will be fire.
|
||||||
*/
|
*/
|
||||||
public void endMapLoad(){
|
public void endMapLoad(){
|
||||||
|
prepareTiles(tiles);
|
||||||
|
|
||||||
for(int x = 0; x < tiles.length; x++){
|
for(int x = 0; x < tiles.length; x++){
|
||||||
for(int y = 0; y < tiles[0].length; y++){
|
for(int y = 0; y < tiles[0].length; y++){
|
||||||
Tile tile = tiles[x][y];
|
Tile tile = tiles[x][y];
|
||||||
@@ -188,24 +205,7 @@ public class World implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Zone getZone(){
|
public Zone getZone(){
|
||||||
return content.getByID(ContentType.zone, state.rules.zone);
|
return state.rules.zone;
|
||||||
}
|
|
||||||
|
|
||||||
public void playZone(Zone zone){
|
|
||||||
ui.loadAnd(() -> {
|
|
||||||
logic.reset();
|
|
||||||
state.rules = zone.rules.get();
|
|
||||||
state.rules.zone = zone.id;
|
|
||||||
loadGenerator(zone.generator);
|
|
||||||
for(Tile core : state.teams.get(defaultTeam).cores){
|
|
||||||
for(ItemStack stack : zone.getStartingItems()){
|
|
||||||
core.entity.items.add(stack.item, stack.amount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state.set(State.playing);
|
|
||||||
control.saves.zoneSave();
|
|
||||||
logic.play();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadGenerator(Generator generator){
|
public void loadGenerator(Generator generator){
|
||||||
@@ -213,24 +213,14 @@ public class World implements ApplicationListener{
|
|||||||
|
|
||||||
createTiles(generator.width, generator.height);
|
createTiles(generator.width, generator.height);
|
||||||
generator.generate(tiles);
|
generator.generate(tiles);
|
||||||
prepareTiles(tiles);
|
|
||||||
|
|
||||||
endMapLoad();
|
endMapLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadMap(Map map){
|
public void loadMap(Map map){
|
||||||
beginMapLoad();
|
|
||||||
this.currentMap = map;
|
|
||||||
|
|
||||||
try{
|
try{
|
||||||
createTiles(map.width, map.height);
|
MapIO.loadMap(map);
|
||||||
for(int x = 0; x < map.width; x++){
|
|
||||||
for(int y = 0; y < map.height; y++){
|
|
||||||
tiles[x][y] = new Tile(x, y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MapIO.readTiles(map, tiles);
|
|
||||||
prepareTiles(tiles);
|
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
if(!headless){
|
if(!headless){
|
||||||
@@ -242,7 +232,7 @@ public class World implements ApplicationListener{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
endMapLoad();
|
this.currentMap = map;
|
||||||
|
|
||||||
invalidMap = false;
|
invalidMap = false;
|
||||||
|
|
||||||
@@ -289,16 +279,7 @@ public class World implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeBlock(Tile tile){
|
public void removeBlock(Tile tile){
|
||||||
if(!tile.block().isMultiblock() && !tile.isLinked()){
|
tile.link().getLinkedTiles(other -> other.setBlock(Blocks.air));
|
||||||
tile.setBlock(Blocks.air);
|
|
||||||
}else{
|
|
||||||
Tile target = tile.target();
|
|
||||||
Array<Tile> removals = target.getLinkedTiles(tempTiles);
|
|
||||||
for(Tile toremove : removals){
|
|
||||||
//note that setting a new block automatically unlinks it
|
|
||||||
if(toremove != null) toremove.setBlock(Blocks.air);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlock(Tile tile, Block block, Team team){
|
public void setBlock(Tile tile, Block block, Team team){
|
||||||
@@ -318,8 +299,7 @@ public class World implements ApplicationListener{
|
|||||||
if(!(worldx == tile.x && worldy == tile.y)){
|
if(!(worldx == tile.x && worldy == tile.y)){
|
||||||
Tile toplace = world.tile(worldx, worldy);
|
Tile toplace = world.tile(worldx, worldy);
|
||||||
if(toplace != null){
|
if(toplace != null){
|
||||||
toplace.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
|
toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team);
|
||||||
toplace.setTeam(team);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,15 +307,6 @@ public class World implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int transform(int packed, int oldWidth, int oldHeight, int newWidth, int shiftX, int shiftY){
|
|
||||||
int x = packed % oldWidth;
|
|
||||||
int y = packed / oldWidth;
|
|
||||||
if(!Structs.inBounds(x, y, oldWidth, oldHeight)) return -1;
|
|
||||||
x += shiftX;
|
|
||||||
y += shiftY;
|
|
||||||
return y * newWidth + x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raycast, but with world coordinates.
|
* Raycast, but with world coordinates.
|
||||||
*/
|
*/
|
||||||
@@ -413,11 +384,6 @@ public class World implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Loads raw map tile data into a Tile[][] array, setting up multiblocks, cliffs and ores. */
|
|
||||||
void loadTileData(Tile[][] tiles){
|
|
||||||
prepareTiles(tiles);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addDarkness(Tile[][] tiles){
|
public void addDarkness(Tile[][] tiles){
|
||||||
byte[][] dark = new byte[tiles.length][tiles[0].length];
|
byte[][] dark = new byte[tiles.length][tiles[0].length];
|
||||||
byte[][] writeBuffer = new byte[tiles.length][tiles[0].length];
|
byte[][] writeBuffer = new byte[tiles.length][tiles[0].length];
|
||||||
@@ -456,7 +422,7 @@ public class World implements ApplicationListener{
|
|||||||
for(int y = 0; y < tiles[0].length; y++){
|
for(int y = 0; y < tiles[0].length; y++){
|
||||||
Tile tile = tiles[x][y];
|
Tile tile = tiles[x][y];
|
||||||
if(tile.block().solid && !tile.block().synthetic()){
|
if(tile.block().solid && !tile.block().synthetic()){
|
||||||
tiles[x][y].setRotation(dark[x][y]);
|
tiles[x][y].rotation(dark[x][y]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -503,25 +469,47 @@ public class World implements ApplicationListener{
|
|||||||
if(!(worldx == x && worldy == y)){
|
if(!(worldx == x && worldy == y)){
|
||||||
Tile toplace = world.tile(worldx, worldy);
|
Tile toplace = world.tile(worldx, worldy);
|
||||||
if(toplace != null){
|
if(toplace != null){
|
||||||
toplace.setLinked((byte)(dx + offsetx), (byte)(dy + offsety));
|
toplace.setBlock(BlockPart.get(dx + offsetx, dy + offsety), team);
|
||||||
toplace.setTeam(team);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//update cliffs, occlusion data
|
|
||||||
for(int x = 0; x < tiles.length; x++){
|
|
||||||
for(int y = 0; y < tiles[0].length; y++){
|
|
||||||
Tile tile = tiles[x][y];
|
|
||||||
|
|
||||||
tile.updateOcclusion();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Raycaster{
|
public interface Raycaster{
|
||||||
boolean accept(int x, int y);
|
boolean accept(int x, int y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Context implements WorldContext{
|
||||||
|
@Override
|
||||||
|
public Tile tile(int x, int y){
|
||||||
|
return tiles[x][y];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resize(int width, int height){
|
||||||
|
createTiles(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tile create(int x, int y, int floorID, int overlayID, int wallID){
|
||||||
|
return (tiles[x][y] = new Tile(x, y, floorID, overlayID, wallID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGenerating(){
|
||||||
|
return World.this.isGenerating();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(){
|
||||||
|
beginMapLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end(){
|
||||||
|
endMapLoad();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.anuke.mindustry.world.Tile;
|
|||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.content;
|
import static io.anuke.mindustry.Vars.content;
|
||||||
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class DrawOperation{
|
public class DrawOperation{
|
||||||
private LongArray array = new LongArray();
|
private LongArray array = new LongArray();
|
||||||
@@ -24,32 +25,46 @@ public class DrawOperation{
|
|||||||
public void undo(MapEditor editor){
|
public void undo(MapEditor editor){
|
||||||
for(int i = array.size - 1; i >= 0; i--){
|
for(int i = array.size - 1; i >= 0; i--){
|
||||||
long l = array.get(i);
|
long l = array.get(i);
|
||||||
set(editor, editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.from(l));
|
array.set(i, TileOp.get(TileOp.x(l), TileOp.y(l), TileOp.type(l), get(editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l))));
|
||||||
|
set(editor, editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.value(l));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void redo(MapEditor editor){
|
public void redo(MapEditor editor){
|
||||||
for(int i = 0; i < array.size; i++){
|
for(int i = 0; i < array.size; i++){
|
||||||
long l = array.get(i);
|
long l = array.get(i);
|
||||||
set(editor, editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.to(l));
|
array.set(i, TileOp.get(TileOp.x(l), TileOp.y(l), TileOp.type(l), get(editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l))));
|
||||||
|
set(editor, editor.tile(TileOp.x(l), TileOp.y(l)), TileOp.type(l), TileOp.value(l));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void set(MapEditor editor, Tile tile, byte type, byte to){
|
short get(Tile tile, byte type){
|
||||||
|
if(type == OpType.floor.ordinal()){
|
||||||
|
return tile.floorID();
|
||||||
|
}else if(type == OpType.block.ordinal()){
|
||||||
|
return tile.blockID();
|
||||||
|
}else if(type == OpType.rotation.ordinal()){
|
||||||
|
return tile.rotation();
|
||||||
|
}else if(type == OpType.team.ordinal()){
|
||||||
|
return tile.getTeamID();
|
||||||
|
}else if(type == OpType.overlay.ordinal()){
|
||||||
|
return tile.overlayID();
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Invalid type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void set(MapEditor editor, Tile tile, byte type, short to){
|
||||||
editor.load(() -> {
|
editor.load(() -> {
|
||||||
if(type == OpType.floor.ordinal()){
|
if(type == OpType.floor.ordinal()){
|
||||||
tile.setFloor((Floor)content.block(to));
|
tile.setFloor((Floor)content.block(to));
|
||||||
}else if(type == OpType.block.ordinal()){
|
}else if(type == OpType.block.ordinal()){
|
||||||
Block block = content.block(to);
|
Block block = content.block(to);
|
||||||
tile.setBlock(block);
|
world.setBlock(tile, block, tile.getTeam(), tile.rotation());
|
||||||
if(block.isMultiblock()){
|
|
||||||
editor.updateLinks(block, tile.x, tile.y);
|
|
||||||
}
|
|
||||||
}else if(type == OpType.rotation.ordinal()){
|
}else if(type == OpType.rotation.ordinal()){
|
||||||
tile.setRotation(to);
|
tile.rotation(to);
|
||||||
}else if(type == OpType.team.ordinal()){
|
}else if(type == OpType.team.ordinal()){
|
||||||
tile.setTeam(Team.all[to]);
|
tile.setTeam(Team.all[to]);
|
||||||
}else if(type == OpType.ore.ordinal()){
|
}else if(type == OpType.overlay.ordinal()){
|
||||||
tile.setOverlayID(to);
|
tile.setOverlayID(to);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -61,8 +76,7 @@ public class DrawOperation{
|
|||||||
short x;
|
short x;
|
||||||
short y;
|
short y;
|
||||||
byte type;
|
byte type;
|
||||||
byte from;
|
short value;
|
||||||
byte to;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum OpType{
|
public enum OpType{
|
||||||
@@ -70,6 +84,6 @@ public class DrawOperation{
|
|||||||
block,
|
block,
|
||||||
rotation,
|
rotation,
|
||||||
team,
|
team,
|
||||||
ore
|
overlay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.editor.DrawOperation.OpType;
|
import io.anuke.mindustry.editor.DrawOperation.OpType;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.gen.TileOp;
|
import io.anuke.mindustry.gen.TileOp;
|
||||||
@@ -9,21 +10,23 @@ import io.anuke.mindustry.world.Tile;
|
|||||||
import io.anuke.mindustry.world.blocks.*;
|
import io.anuke.mindustry.world.blocks.*;
|
||||||
import io.anuke.mindustry.world.modules.*;
|
import io.anuke.mindustry.world.modules.*;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.state;
|
||||||
import static io.anuke.mindustry.Vars.ui;
|
import static io.anuke.mindustry.Vars.ui;
|
||||||
|
|
||||||
|
//TODO somehow remove or replace this class with a more flexible solution
|
||||||
public class EditorTile extends Tile{
|
public class EditorTile extends Tile{
|
||||||
|
|
||||||
public EditorTile(int x, int y, byte floor, byte wall){
|
public EditorTile(int x, int y, int floor, int overlay, int wall){
|
||||||
super(x, y, floor, wall);
|
super(x, y, floor, overlay, wall);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Team getTeam(){
|
|
||||||
return Team.all[getTeamID()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setFloor(Floor type){
|
public void setFloor(Floor type){
|
||||||
|
if(state.is(State.playing)){
|
||||||
|
super.setFloor(type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(type instanceof OverlayFloor){
|
if(type instanceof OverlayFloor){
|
||||||
//don't place on liquids
|
//don't place on liquids
|
||||||
if(!floor.isLiquid){
|
if(!floor.isLiquid){
|
||||||
@@ -32,63 +35,91 @@ public class EditorTile extends Tile{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block previous = floor();
|
if(floor == type && overlayID() == 0) return;
|
||||||
Block ore = overlay();
|
if(overlayID() != 0) op(OpType.overlay, overlayID());
|
||||||
if(previous == type && ore == Blocks.air) return;
|
if(floor != type) op(OpType.floor, floor.id);
|
||||||
super.setFloor(type);
|
super.setFloor(type);
|
||||||
//ore may get nullified so make sure to save edits
|
|
||||||
if(overlay() != ore){
|
|
||||||
op(TileOp.get(x, y, (byte)OpType.ore.ordinal(), ore.id, overlay().id));
|
|
||||||
}
|
|
||||||
if(previous != type){
|
|
||||||
op(TileOp.get(x, y, (byte)OpType.floor.ordinal(), previous.id, type.id));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBlock(Block type){
|
public void setBlock(Block type){
|
||||||
Block previous = block;
|
if(state.is(State.playing)){
|
||||||
byte pteam = getTeamID();
|
super.setBlock(type);
|
||||||
if(previous == type) return;
|
return;
|
||||||
super.setBlock(type);
|
|
||||||
if(pteam != getTeamID()){
|
|
||||||
op(TileOp.get(x, y, (byte)OpType.team.ordinal(), pteam, getTeamID()));
|
|
||||||
}
|
}
|
||||||
op(TileOp.get(x, y, (byte)OpType.block.ordinal(), previous.id, type.id));
|
|
||||||
|
|
||||||
|
if(block == type) return;
|
||||||
|
op(OpType.block, block.id);
|
||||||
|
if(rotation != 0) op(OpType.rotation, rotation);
|
||||||
|
if(team != 0) op(OpType.team, team);
|
||||||
|
super.setBlock(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBlock(Block type, Team team, int rotation){
|
||||||
|
if(state.is(State.playing)){
|
||||||
|
super.setBlock(type, team, rotation);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setBlock(type);
|
||||||
|
setTeam(team);
|
||||||
|
rotation(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setTeam(Team team){
|
public void setTeam(Team team){
|
||||||
byte previous = getTeamID();
|
if(state.is(State.playing)){
|
||||||
if(previous == team.ordinal()) return;
|
super.setTeam(team);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getTeamID() == team.ordinal()) return;
|
||||||
|
op(OpType.team, getTeamID());
|
||||||
super.setTeam(team);
|
super.setTeam(team);
|
||||||
op(TileOp.get(x, y, (byte)OpType.team.ordinal(), previous, (byte)team.ordinal()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRotation(byte rotation){
|
public void rotation(int rotation){
|
||||||
byte previous = getRotation();
|
if(state.is(State.playing)){
|
||||||
if(previous == rotation) return;
|
super.rotation(rotation);
|
||||||
super.setRotation(rotation);
|
return;
|
||||||
op(TileOp.get(x, y, (byte)OpType.rotation.ordinal(), previous, rotation));
|
}
|
||||||
|
|
||||||
|
if(rotation == rotation()) return;
|
||||||
|
op(OpType.rotation, rotation());
|
||||||
|
super.rotation(rotation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOverlayID(byte ore){
|
public void setOverlayID(short overlay){
|
||||||
byte previous = getOverlayID();
|
if(state.is(State.playing)){
|
||||||
if(previous == ore) return;
|
super.setOverlayID(overlay);
|
||||||
super.setOverlayID(ore);
|
return;
|
||||||
op(TileOp.get(x, y, (byte)OpType.ore.ordinal(), previous, ore));
|
}
|
||||||
|
|
||||||
|
if(overlayID() == overlay) return;
|
||||||
|
op(OpType.overlay, overlay);
|
||||||
|
super.setOverlayID(overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void preChanged(){
|
protected void preChanged(){
|
||||||
|
if(state.is(State.playing)){
|
||||||
|
super.preChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
super.setTeam(Team.none);
|
super.setTeam(Team.none);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void changed(){
|
protected void changed(){
|
||||||
|
if(state.is(State.playing)){
|
||||||
|
super.changed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
entity = null;
|
entity = null;
|
||||||
|
|
||||||
if(block == null){
|
if(block == null){
|
||||||
@@ -102,8 +133,7 @@ public class EditorTile extends Tile{
|
|||||||
Block block = block();
|
Block block = block();
|
||||||
|
|
||||||
if(block.hasEntity()){
|
if(block.hasEntity()){
|
||||||
entity = block.newEntity();
|
entity = block.newEntity().init(this, false);
|
||||||
entity.health = block.health;
|
|
||||||
entity.cons = new ConsumeModule(entity);
|
entity.cons = new ConsumeModule(entity);
|
||||||
if(block.hasItems) entity.items = new ItemModule();
|
if(block.hasItems) entity.items = new ItemModule();
|
||||||
if(block.hasLiquids) entity.liquids = new LiquidModule();
|
if(block.hasLiquids) entity.liquids = new LiquidModule();
|
||||||
@@ -111,7 +141,7 @@ public class EditorTile extends Tile{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void op(long op){
|
private void op(OpType type, short value){
|
||||||
ui.editor.editor.addTileOp(op);
|
ui.editor.editor.addTileOp(TileOp.get(x, y, (byte)type.ordinal(), value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,21 +15,7 @@ public enum EditorTool{
|
|||||||
public void touched(MapEditor editor, int x, int y){
|
public void touched(MapEditor editor, int x, int y){
|
||||||
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
|
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
|
||||||
|
|
||||||
Tile tile = editor.tile(x, y);
|
Tile tile = editor.tile(x, y).link();
|
||||||
|
|
||||||
byte link = tile.getLinkByte();
|
|
||||||
|
|
||||||
if(tile.isLinked()){
|
|
||||||
x -= (Pack.leftByte(link) - 8);
|
|
||||||
y -= (Pack.rightByte(link) - 8);
|
|
||||||
|
|
||||||
tile = editor.tile(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
//do not.
|
|
||||||
if(tile.isLinked()){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.drawBlock = tile.block() == Blocks.air ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block();
|
editor.drawBlock = tile.block() == Blocks.air ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block();
|
||||||
}
|
}
|
||||||
@@ -87,7 +73,7 @@ public enum EditorTool{
|
|||||||
Block draw = editor.drawBlock;
|
Block draw = editor.drawBlock;
|
||||||
dest = draw instanceof OverlayFloor ? tile.overlay() : isfloor ? floor : block;
|
dest = draw instanceof OverlayFloor ? tile.overlay() : isfloor ? floor : block;
|
||||||
|
|
||||||
if(dest == draw || block == Blocks.part || block.isMultiblock()){
|
if(dest == draw || block instanceof BlockPart || block.isMultiblock()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +102,7 @@ public enum EditorTool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(draw.rotate){
|
if(draw.rotate){
|
||||||
write.setRotation((byte)editor.rotation);
|
write.rotation((byte)editor.rotation);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,28 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.arc.collection.ObjectMap;
|
import io.anuke.arc.collection.StringMap;
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.FileHandle;
|
||||||
|
import io.anuke.arc.graphics.Pixmap;
|
||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.util.Pack;
|
|
||||||
import io.anuke.arc.util.Structs;
|
import io.anuke.arc.util.Structs;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.gen.TileOp;
|
import io.anuke.mindustry.gen.TileOp;
|
||||||
|
import io.anuke.mindustry.io.LegacyMapIO;
|
||||||
import io.anuke.mindustry.io.MapIO;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.*;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
|
||||||
import java.io.IOException;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public class MapEditor{
|
public class MapEditor{
|
||||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15, 20};
|
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15, 20};
|
||||||
|
|
||||||
private ObjectMap<String, String> tags = new ObjectMap<>();
|
private final Context context = new Context();
|
||||||
|
private StringMap tags = new StringMap();
|
||||||
private MapRenderer renderer = new MapRenderer(this);
|
private MapRenderer renderer = new MapRenderer(this);
|
||||||
private Tile[][] tiles;
|
|
||||||
|
|
||||||
private OperationStack stack = new OperationStack();
|
private OperationStack stack = new OperationStack();
|
||||||
private DrawOperation currentOp;
|
private DrawOperation currentOp;
|
||||||
@@ -32,7 +33,7 @@ public class MapEditor{
|
|||||||
public Block drawBlock = Blocks.stone;
|
public Block drawBlock = Blocks.stone;
|
||||||
public Team drawTeam = Team.blue;
|
public Team drawTeam = Team.blue;
|
||||||
|
|
||||||
public ObjectMap<String, String> getTags(){
|
public StringMap getTags(){
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,39 +41,39 @@ public class MapEditor{
|
|||||||
reset();
|
reset();
|
||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
tiles = createTiles(width, height);
|
createTiles(width, height);
|
||||||
renderer.resize(width(), height());
|
renderer.resize(width(), height());
|
||||||
loading = false;
|
loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beginEdit(Map map) throws IOException{
|
public void beginEdit(Map map){
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
loading = true;
|
loading = true;
|
||||||
tiles = createTiles(map.width, map.height);
|
|
||||||
tags.putAll(map.tags);
|
tags.putAll(map.tags);
|
||||||
MapIO.readTiles(map, tiles);
|
MapIO.loadMap(map, context);
|
||||||
checkLinkedTiles();
|
checkLinkedTiles();
|
||||||
renderer.resize(width(), height());
|
renderer.resize(width(), height());
|
||||||
loading = false;
|
loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void beginEdit(Tile[][] tiles){
|
public void beginEdit(Pixmap pixmap){
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
this.tiles = tiles;
|
createTiles(pixmap.getWidth(), pixmap.getHeight());
|
||||||
checkLinkedTiles();
|
load(() -> LegacyMapIO.readPixmap(pixmap, tiles()));
|
||||||
renderer.resize(width(), height());
|
renderer.resize(width(), height());
|
||||||
}
|
}
|
||||||
|
|
||||||
//adds missing blockparts
|
//adds missing blockparts
|
||||||
public void checkLinkedTiles(){
|
public void checkLinkedTiles(){
|
||||||
|
Tile[][] tiles = world.getTiles();
|
||||||
|
|
||||||
//clear block parts first
|
//clear block parts first
|
||||||
for(int x = 0; x < width(); x++){
|
for(int x = 0; x < width(); x++){
|
||||||
for(int y = 0; y < height(); y++){
|
for(int y = 0; y < height(); y++){
|
||||||
if(tiles[x][y].block() == Blocks.part){
|
if(tiles[x][y].block() instanceof BlockPart){
|
||||||
tiles[x][y].setBlock(Blocks.air);
|
tiles[x][y].setBlock(Blocks.air);
|
||||||
tiles[x][y].setLinkByte((byte)0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,22 +81,8 @@ public class MapEditor{
|
|||||||
//set up missing blockparts
|
//set up missing blockparts
|
||||||
for(int x = 0; x < width(); x++){
|
for(int x = 0; x < width(); x++){
|
||||||
for(int y = 0; y < height(); y++){
|
for(int y = 0; y < height(); y++){
|
||||||
Block drawBlock = tiles[x][y].block();
|
if(tiles[x][y].block().isMultiblock()){
|
||||||
if(drawBlock.isMultiblock()){
|
world.setBlock(tiles[x][y], tiles[x][y].block(), tiles[x][y].getTeam());
|
||||||
int offsetx = -(drawBlock.size - 1) / 2;
|
|
||||||
int offsety = -(drawBlock.size - 1) / 2;
|
|
||||||
for(int dx = 0; dx < drawBlock.size; dx++){
|
|
||||||
for(int dy = 0; dy < drawBlock.size; dy++){
|
|
||||||
int worldx = dx + offsetx + x;
|
|
||||||
int worldy = dy + offsety + y;
|
|
||||||
|
|
||||||
if(Structs.inBounds(worldx, worldy, width(), height()) && !(dx + offsetx == 0 && dy + offsety == 0)){
|
|
||||||
Tile tile = tiles[worldx][worldy];
|
|
||||||
tile.setBlock(Blocks.part);
|
|
||||||
tile.setLinkByte(Pack.byteByte((byte)(dx + offsetx + 8), (byte)(dy + offsety + 8)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,63 +95,41 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a 2-D array of EditorTiles with stone as the floor block. */
|
/** Creates a 2-D array of EditorTiles with stone as the floor block. */
|
||||||
public Tile[][] createTiles(int width, int height){
|
private void createTiles(int width, int height){
|
||||||
tiles = new Tile[width][height];
|
Tile[][] tiles = world.createTiles(width, height);
|
||||||
|
|
||||||
for(int x = 0; x < width; x++){
|
for(int x = 0; x < width; x++){
|
||||||
for(int y = 0; y < height; y++){
|
for(int y = 0; y < height; y++){
|
||||||
tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (byte)0);
|
tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tiles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map createMap(FileHandle file){
|
public Map createMap(FileHandle file){
|
||||||
return new Map(file, width(), height(), new ObjectMap<>(tags), true);
|
return new Map(file, width(), height(), new StringMap(tags), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void reset(){
|
private void reset(){
|
||||||
clearOp();
|
clearOp();
|
||||||
brushSize = 1;
|
brushSize = 1;
|
||||||
drawBlock = Blocks.stone;
|
drawBlock = Blocks.stone;
|
||||||
tags = new ObjectMap<>();
|
tags = new StringMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tile[][] tiles(){
|
public Tile[][] tiles(){
|
||||||
return tiles;
|
return world.getTiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Tile tile(int x, int y){
|
public Tile tile(int x, int y){
|
||||||
return tiles[x][y];
|
return world.rawTile(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int width(){
|
public int width(){
|
||||||
return tiles.length;
|
return world.width();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int height(){
|
public int height(){
|
||||||
return tiles[0].length;
|
return world.height();
|
||||||
}
|
|
||||||
|
|
||||||
public void updateLinks(Block block, int x, int y){
|
|
||||||
int offsetx = -(block.size - 1) / 2;
|
|
||||||
int offsety = -(block.size - 1) / 2;
|
|
||||||
|
|
||||||
for(int dx = 0; dx < block.size; dx++){
|
|
||||||
for(int dy = 0; dy < block.size; dy++){
|
|
||||||
int worldx = dx + offsetx + x;
|
|
||||||
int worldy = dy + offsety + y;
|
|
||||||
|
|
||||||
if(Structs.inBounds(worldx, worldy, width(), height())){
|
|
||||||
Tile tile = tiles[worldx][worldy];
|
|
||||||
|
|
||||||
if(!(worldx == x && worldy == y)){
|
|
||||||
tile.setBlock(Blocks.part);
|
|
||||||
tile.setLinkByte(Pack.byteByte((byte)(dx + offsetx + 8), (byte)(dy + offsety + 8)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void draw(int x, int y, boolean paint){
|
public void draw(int x, int y, boolean paint){
|
||||||
@@ -177,45 +142,36 @@ public class MapEditor{
|
|||||||
|
|
||||||
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
|
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
|
||||||
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
||||||
|
Tile[][] tiles = world.getTiles();
|
||||||
|
|
||||||
if(drawBlock.isMultiblock()){
|
if(drawBlock.isMultiblock()){
|
||||||
|
|
||||||
x = Mathf.clamp(x, (drawBlock.size - 1) / 2, width() - drawBlock.size / 2 - 1);
|
x = Mathf.clamp(x, (drawBlock.size - 1) / 2, width() - drawBlock.size / 2 - 1);
|
||||||
y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1);
|
y = Mathf.clamp(y, (drawBlock.size - 1) / 2, height() - drawBlock.size / 2 - 1);
|
||||||
|
|
||||||
int offsetx = -(drawBlock.size - 1) / 2;
|
int offsetx = -(drawBlock.size - 1) / 2;
|
||||||
int offsety = -(drawBlock.size - 1) / 2;
|
int offsety = -(drawBlock.size - 1) / 2;
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++){
|
for(int dx = 0; dx < drawBlock.size; dx++){
|
||||||
for(int dx = 0; dx < drawBlock.size; dx++){
|
for(int dy = 0; dy < drawBlock.size; dy++){
|
||||||
for(int dy = 0; dy < drawBlock.size; dy++){
|
int worldx = dx + offsetx + x;
|
||||||
int worldx = dx + offsetx + x;
|
int worldy = dy + offsety + y;
|
||||||
int worldy = dy + offsety + y;
|
|
||||||
|
|
||||||
if(Structs.inBounds(worldx, worldy, width(), height())){
|
if(Structs.inBounds(worldx, worldy, width(), height())){
|
||||||
Tile tile = tiles[worldx][worldy];
|
Tile tile = tiles[worldx][worldy];
|
||||||
|
|
||||||
if(i == 1){
|
Block block = tile.block();
|
||||||
tile.setBlock(Blocks.part);
|
|
||||||
tile.setLinkByte(Pack.byteByte((byte)(dx + offsetx + 8), (byte)(dy + offsety + 8)));
|
|
||||||
}else{
|
|
||||||
byte link = tile.getLinkByte();
|
|
||||||
Block block = tile.block();
|
|
||||||
|
|
||||||
if(link != 0){
|
//bail out if there's anything blocking the way
|
||||||
removeLinked(worldx - (Pack.leftByte(link) - 8), worldy - (Pack.rightByte(link) - 8));
|
if(block.isMultiblock() || block instanceof BlockPart){
|
||||||
}else if(block.isMultiblock()){
|
return;
|
||||||
removeLinked(worldx, worldy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderer.updatePoint(worldx, worldy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Tile tile = tiles[x][y];
|
world.setBlock(tiles[x][y], drawBlock, drawTeam);
|
||||||
tile.setBlock(drawBlock);
|
|
||||||
tile.setTeam(drawTeam);
|
|
||||||
}else{
|
}else{
|
||||||
for(int rx = -brushSize; rx <= brushSize; rx++){
|
for(int rx = -brushSize; rx <= brushSize; rx++){
|
||||||
for(int ry = -brushSize; ry <= brushSize; ry++){
|
for(int ry = -brushSize; ry <= brushSize; ry++){
|
||||||
@@ -228,14 +184,8 @@ public class MapEditor{
|
|||||||
|
|
||||||
Tile tile = tiles[wx][wy];
|
Tile tile = tiles[wx][wy];
|
||||||
|
|
||||||
if(!isfloor){
|
if(!isfloor && (tile.isLinked() || tile.block().isMultiblock())){
|
||||||
byte link = tile.getLinkByte();
|
world.removeBlock(tile.link());
|
||||||
|
|
||||||
if(tile.block().isMultiblock()){
|
|
||||||
removeLinked(wx, wy);
|
|
||||||
}else if(link != 0 && tiles[wx][wy].block() == Blocks.part){
|
|
||||||
removeLinked(wx - (Pack.leftByte(link) - 8), wy - (Pack.rightByte(link) - 8));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isfloor){
|
if(isfloor){
|
||||||
@@ -246,7 +196,7 @@ public class MapEditor{
|
|||||||
tile.setTeam(drawTeam);
|
tile.setTeam(drawTeam);
|
||||||
}
|
}
|
||||||
if(drawBlock.rotate){
|
if(drawBlock.rotate){
|
||||||
tile.setRotation((byte)rotation);
|
tile.rotation((byte)rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -255,22 +205,6 @@ public class MapEditor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeLinked(int x, int y){
|
|
||||||
Block block = tiles[x][y].block();
|
|
||||||
|
|
||||||
int offsetx = -(block.size - 1) / 2;
|
|
||||||
int offsety = -(block.size - 1) / 2;
|
|
||||||
for(int dx = 0; dx < block.size; dx++){
|
|
||||||
for(int dy = 0; dy < block.size; dy++){
|
|
||||||
int worldx = x + dx + offsetx, worldy = y + dy + offsety;
|
|
||||||
if(Structs.inBounds(worldx, worldy, width(), height())){
|
|
||||||
tiles[worldx][worldy].setTeam(Team.none);
|
|
||||||
tiles[worldx][worldy].setBlock(Blocks.air);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapRenderer renderer(){
|
public MapRenderer renderer(){
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
@@ -278,11 +212,11 @@ public class MapEditor{
|
|||||||
public void resize(int width, int height){
|
public void resize(int width, int height){
|
||||||
clearOp();
|
clearOp();
|
||||||
|
|
||||||
Tile[][] previous = tiles;
|
Tile[][] previous = world.getTiles();
|
||||||
int offsetX = -(width - width()) / 2, offsetY = -(height - height()) / 2;
|
int offsetX = -(width - width()) / 2, offsetY = -(height - height()) / 2;
|
||||||
loading = true;
|
loading = true;
|
||||||
|
|
||||||
tiles = new Tile[width][height];
|
Tile[][] tiles = world.createTiles(width, height);
|
||||||
for(int x = 0; x < width; x++){
|
for(int x = 0; x < width; x++){
|
||||||
for(int y = 0; y < height; y++){
|
for(int y = 0; y < height; y++){
|
||||||
int px = offsetX + x, py = offsetY + y;
|
int px = offsetX + x, py = offsetY + y;
|
||||||
@@ -291,7 +225,7 @@ public class MapEditor{
|
|||||||
tiles[x][y].x = (short)x;
|
tiles[x][y].x = (short)x;
|
||||||
tiles[x][y].y = (short)y;
|
tiles[x][y].y = (short)y;
|
||||||
}else{
|
}else{
|
||||||
tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (byte)0);
|
tiles[x][y] = new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -338,4 +272,36 @@ public class MapEditor{
|
|||||||
|
|
||||||
renderer.updatePoint(TileOp.x(data), TileOp.y(data));
|
renderer.updatePoint(TileOp.x(data), TileOp.y(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class Context implements WorldContext{
|
||||||
|
@Override
|
||||||
|
public Tile tile(int x, int y){
|
||||||
|
return world.tile(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resize(int width, int height){
|
||||||
|
world.createTiles(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tile create(int x, int y, int floorID, int overlayID, int wallID){
|
||||||
|
return (tiles()[x][y] = new EditorTile(x, y, floorID, overlayID, wallID));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGenerating(){
|
||||||
|
return world.isGenerating();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin(){
|
||||||
|
world.beginMapLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void end(){
|
||||||
|
world.endMapLoad();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.editor;
|
|||||||
|
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
|
import io.anuke.arc.collection.StringMap;
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.function.Consumer;
|
import io.anuke.arc.function.Consumer;
|
||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
@@ -17,8 +18,10 @@ import io.anuke.arc.scene.ui.layout.Table;
|
|||||||
import io.anuke.arc.scene.ui.layout.Unit;
|
import io.anuke.arc.scene.ui.layout.Unit;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.mindustry.Vars;
|
import io.anuke.mindustry.Vars;
|
||||||
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.core.Platform;
|
import io.anuke.mindustry.core.Platform;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.*;
|
||||||
|
import io.anuke.mindustry.io.JsonIO;
|
||||||
import io.anuke.mindustry.io.MapIO;
|
import io.anuke.mindustry.io.MapIO;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
@@ -40,6 +43,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
private MapGenerateDialog generateDialog;
|
private MapGenerateDialog generateDialog;
|
||||||
private ScrollPane pane;
|
private ScrollPane pane;
|
||||||
private FloatingDialog menu;
|
private FloatingDialog menu;
|
||||||
|
private Rules lastSavedRules;
|
||||||
private boolean saved = false;
|
private boolean saved = false;
|
||||||
private boolean shownWithMap = false;
|
private boolean shownWithMap = false;
|
||||||
private Array<Block> blocksOut = new Array<>();
|
private Array<Block> blocksOut = new Array<>();
|
||||||
@@ -91,7 +95,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
Platform.instance.showFileChooser("$editor.loadmap", "Map Files", file -> ui.loadAnd(() -> {
|
Platform.instance.showFileChooser("$editor.loadmap", "Map Files", file -> ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
//TODO what if it's an image? users should be warned for their stupidity
|
//TODO what if it's an image? users should be warned for their stupidity
|
||||||
editor.beginEdit(MapIO.readMap(file, true));
|
editor.beginEdit(MapIO.createMap(file, true));
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
@@ -103,9 +107,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
Pixmap pixmap = new Pixmap(file);
|
Pixmap pixmap = new Pixmap(file);
|
||||||
Tile[][] tiles = editor.createTiles(pixmap.getWidth(), pixmap.getHeight());
|
editor.beginEdit(pixmap);
|
||||||
editor.load(() -> MapIO.readLegacyPixmap(pixmap, tiles));
|
pixmap.dispose();
|
||||||
editor.beginEdit(tiles);
|
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
@@ -122,7 +125,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
if(!editor.getTags().containsKey("name")){
|
if(!editor.getTags().containsKey("name")){
|
||||||
editor.getTags().put("name", result.nameWithoutExtension());
|
editor.getTags().put("name", result.nameWithoutExtension());
|
||||||
}
|
}
|
||||||
MapIO.writeMap(result, editor.createMap(result), editor.tiles());
|
MapIO.writeMap(result, editor.createMap(result));
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, false)));
|
ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, false)));
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
@@ -133,10 +136,14 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
menu.cont.row();
|
menu.cont.row();
|
||||||
|
|
||||||
|
menu.cont.addImageTextButton("$editor.ingame", "icon-arrow", isize, this::playtest).padTop(-5).size(swidth * 2f + 10, 60f);
|
||||||
|
|
||||||
|
menu.cont.row();
|
||||||
|
|
||||||
menu.cont.addImageTextButton("$quit", "icon-back", isize, () -> {
|
menu.cont.addImageTextButton("$quit", "icon-back", isize, () -> {
|
||||||
tryExit();
|
tryExit();
|
||||||
menu.hide();
|
menu.hide();
|
||||||
}).padTop(-5).size(swidth * 2f + 10, 60f);
|
}).size(swidth * 2f + 10, 60f);
|
||||||
|
|
||||||
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
|
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
|
||||||
if(!(editor.width() == x && editor.height() == y)){
|
if(!(editor.width() == x && editor.height() == y)){
|
||||||
@@ -181,11 +188,14 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
});
|
});
|
||||||
|
|
||||||
shown(() -> {
|
shown(() -> {
|
||||||
|
//clear units, rules and other unnecessary stuff
|
||||||
|
logic.reset();
|
||||||
saved = true;
|
saved = true;
|
||||||
if(!Core.settings.getBool("landscape")) Platform.instance.beginForceLandscape();
|
if(!Core.settings.getBool("landscape")) Platform.instance.beginForceLandscape();
|
||||||
editor.clearOp();
|
editor.clearOp();
|
||||||
Core.scene.setScrollFocus(view);
|
Core.scene.setScrollFocus(view);
|
||||||
if(!shownWithMap){
|
if(!shownWithMap){
|
||||||
|
state.rules = new Rules();
|
||||||
editor.beginEdit(200, 200);
|
editor.beginEdit(200, 200);
|
||||||
}
|
}
|
||||||
shownWithMap = false;
|
shownWithMap = false;
|
||||||
@@ -205,8 +215,47 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
drawDefaultBackground(x, y);
|
drawDefaultBackground(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void resumeEditing(){
|
||||||
|
state.set(State.menu);
|
||||||
|
shownWithMap = true;
|
||||||
|
show();
|
||||||
|
state.rules = (lastSavedRules == null ? new Rules() : lastSavedRules);
|
||||||
|
lastSavedRules = null;
|
||||||
|
editor.renderer().updateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playtest(){
|
||||||
|
menu.hide();
|
||||||
|
ui.loadAnd(() -> {
|
||||||
|
lastSavedRules = state.rules;
|
||||||
|
hide();
|
||||||
|
//only reset the player; logic.reset() will clear entities, which we do not want
|
||||||
|
player.reset();
|
||||||
|
state.rules = Gamemode.editor.apply(new Rules());
|
||||||
|
world.setMap(new Map(StringMap.of(
|
||||||
|
"name", "Editor Playtesting",
|
||||||
|
"width", editor.width(),
|
||||||
|
"height", editor.height()
|
||||||
|
)));
|
||||||
|
world.endMapLoad();
|
||||||
|
//add entities so they update. is this really needed?
|
||||||
|
for(int x = 0; x < world.width(); x++){
|
||||||
|
for(int y = 0; y < world.height(); y++){
|
||||||
|
Tile tile = world.rawTile(x, y);
|
||||||
|
if(tile.entity != null){
|
||||||
|
tile.entity.add();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player.set(world.width() * tilesize/2f, world.height() * tilesize/2f);
|
||||||
|
player.setDead(false);
|
||||||
|
logic.play();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void save(){
|
private void save(){
|
||||||
String name = editor.getTags().get("name", "").trim();
|
String name = editor.getTags().get("name", "").trim();
|
||||||
|
editor.getTags().put("rules", JsonIO.write(state.rules));
|
||||||
|
|
||||||
if(name.isEmpty()){
|
if(name.isEmpty()){
|
||||||
infoDialog.show();
|
infoDialog.show();
|
||||||
@@ -216,7 +265,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
if(map != null && !map.custom){
|
if(map != null && !map.custom){
|
||||||
ui.showError("$editor.save.overwrite");
|
ui.showError("$editor.save.overwrite");
|
||||||
}else{
|
}else{
|
||||||
world.maps.saveMap(editor.getTags(), editor.tiles());
|
world.maps.saveMap(editor.getTags());
|
||||||
ui.showInfoFade("$editor.saved");
|
ui.showInfoFade("$editor.saved");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,9 +330,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
public void beginEditMap(FileHandle file){
|
public void beginEditMap(FileHandle file){
|
||||||
ui.loadAnd(() -> {
|
ui.loadAnd(() -> {
|
||||||
try{
|
try{
|
||||||
Map map = MapIO.readMap(file, true);
|
|
||||||
shownWithMap = true;
|
shownWithMap = true;
|
||||||
editor.beginEdit(map);
|
editor.beginEdit(MapIO.createMap(file, true));
|
||||||
show();
|
show();
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
Log.err(e);
|
Log.err(e);
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
|||||||
Tile tile = editor.tile(x, y);
|
Tile tile = editor.tile(x, y);
|
||||||
input.begin(editor, x, y, tile.floor(), tile.block(), tile.overlay());
|
input.begin(editor, x, y, tile.floor(), tile.block(), tile.overlay());
|
||||||
filter.apply(input);
|
filter.apply(input);
|
||||||
writeTiles[x][y].set(input.floor, input.block, input.ore, tile.getTeam(), tile.getRotation());
|
writeTiles[x][y].set(input.floor, input.block, input.ore, tile.getTeam(), tile.rotation());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -235,7 +235,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
|||||||
Tile tile = editor.tile(x, y);
|
Tile tile = editor.tile(x, y);
|
||||||
DummyTile write = writeTiles[x][y];
|
DummyTile write = writeTiles[x][y];
|
||||||
|
|
||||||
tile.setRotation(write.rotation);
|
tile.rotation(write.rotation);
|
||||||
tile.setFloor((Floor)content.block(write.floor));
|
tile.setFloor((Floor)content.block(write.floor));
|
||||||
tile.setBlock(content.block(write.block));
|
tile.setBlock(content.block(write.block));
|
||||||
tile.setTeam(Team.all[write.team]);
|
tile.setTeam(Team.all[write.team]);
|
||||||
@@ -322,7 +322,8 @@ public class MapGenerateDialog extends FloatingDialog{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class DummyTile{
|
public static class DummyTile{
|
||||||
public byte block, floor, ore, team, rotation;
|
public byte team, rotation;
|
||||||
|
public short block, floor, ore;
|
||||||
|
|
||||||
void set(Block floor, Block wall, Block ore, Team team, int rotation){
|
void set(Block floor, Block wall, Block ore, Team team, int rotation){
|
||||||
this.floor = floor.id;
|
this.floor = floor.id;
|
||||||
@@ -341,7 +342,7 @@ public class MapGenerateDialog extends FloatingDialog{
|
|||||||
}
|
}
|
||||||
|
|
||||||
void set(Tile other){
|
void set(Tile other){
|
||||||
set(other.floor(), other.block(), other.overlay(), other.getTeam(), other.getRotation());
|
set(other.floor(), other.block(), other.overlay(), other.getTeam(), other.rotation());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ import io.anuke.arc.Core;
|
|||||||
import io.anuke.arc.collection.ObjectMap;
|
import io.anuke.arc.collection.ObjectMap;
|
||||||
import io.anuke.arc.scene.ui.TextArea;
|
import io.anuke.arc.scene.ui.TextArea;
|
||||||
import io.anuke.arc.scene.ui.TextField;
|
import io.anuke.arc.scene.ui.TextField;
|
||||||
|
import io.anuke.mindustry.Vars;
|
||||||
import io.anuke.mindustry.core.Platform;
|
import io.anuke.mindustry.core.Platform;
|
||||||
|
import io.anuke.mindustry.game.Rules;
|
||||||
|
import io.anuke.mindustry.ui.dialogs.CustomRulesDialog;
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
|
|
||||||
public class MapInfoDialog extends FloatingDialog{
|
public class MapInfoDialog extends FloatingDialog{
|
||||||
private final MapEditor editor;
|
private final MapEditor editor;
|
||||||
private final WaveInfoDialog waveinfo;
|
private final WaveInfoDialog waveinfo;
|
||||||
|
private final CustomRulesDialog ruleinfo = new CustomRulesDialog();
|
||||||
|
|
||||||
public MapInfoDialog(MapEditor editor){
|
public MapInfoDialog(MapEditor editor){
|
||||||
super("$editor.mapinfo");
|
super("$editor.mapinfo");
|
||||||
@@ -36,7 +40,6 @@ public class MapInfoDialog extends FloatingDialog{
|
|||||||
name.setMessageText("$unknown");
|
name.setMessageText("$unknown");
|
||||||
|
|
||||||
cont.row();
|
cont.row();
|
||||||
|
|
||||||
cont.add("$editor.description").padRight(8).left();
|
cont.add("$editor.description").padRight(8).left();
|
||||||
|
|
||||||
TextArea description = cont.addArea(tags.get("description", ""), "textarea", text -> {
|
TextArea description = cont.addArea(tags.get("description", ""), "textarea", text -> {
|
||||||
@@ -44,7 +47,6 @@ public class MapInfoDialog extends FloatingDialog{
|
|||||||
}).size(400f, 140f).get();
|
}).size(400f, 140f).get();
|
||||||
|
|
||||||
cont.row();
|
cont.row();
|
||||||
|
|
||||||
cont.add("$editor.author").padRight(8).left();
|
cont.add("$editor.author").padRight(8).left();
|
||||||
|
|
||||||
TextField author = cont.addField(tags.get("author", Core.settings.getString("mapAuthor", "")), text -> {
|
TextField author = cont.addField(tags.get("author", Core.settings.getString("mapAuthor", "")), text -> {
|
||||||
@@ -54,14 +56,13 @@ public class MapInfoDialog extends FloatingDialog{
|
|||||||
}).size(400, 55f).get();
|
}).size(400, 55f).get();
|
||||||
author.setMessageText("$unknown");
|
author.setMessageText("$unknown");
|
||||||
|
|
||||||
|
cont.row();
|
||||||
|
cont.add("$editor.rules").padRight(8).left();
|
||||||
|
cont.addButton("$edit", () -> ruleinfo.show(Vars.state.rules, () -> Vars.state.rules = new Rules())).left().width(200f);;
|
||||||
|
|
||||||
cont.row();
|
cont.row();
|
||||||
cont.add("$editor.waves").padRight(8).left();
|
cont.add("$editor.waves").padRight(8).left();
|
||||||
cont.table(t -> {
|
cont.addButton("$edit", waveinfo::show).left().width(200f);
|
||||||
t.add().growX();
|
|
||||||
t.label(() -> tags.containsKey("waves") ? "" : Core.bundle.get("editor.default")).left();
|
|
||||||
t.add().growX();
|
|
||||||
t.addButton("$edit", waveinfo::show).growY().width(200f);
|
|
||||||
}).size(400, 55f);
|
|
||||||
|
|
||||||
name.change();
|
name.change();
|
||||||
description.change();
|
description.change();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import io.anuke.mindustry.game.Team;
|
|||||||
import io.anuke.mindustry.graphics.IndexedRenderer;
|
import io.anuke.mindustry.graphics.IndexedRenderer;
|
||||||
import io.anuke.mindustry.world.Block;
|
import io.anuke.mindustry.world.Block;
|
||||||
import io.anuke.mindustry.world.Tile;
|
import io.anuke.mindustry.world.Tile;
|
||||||
|
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.tilesize;
|
import static io.anuke.mindustry.Vars.tilesize;
|
||||||
|
|
||||||
@@ -84,7 +85,6 @@ public class MapRenderer implements Disposable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updatePoint(int x, int y){
|
public void updatePoint(int x, int y){
|
||||||
//TODO spread out over multiple frames?
|
|
||||||
updates.add(x + y * width);
|
updates.add(x + y * width);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,13 +110,13 @@ public class MapRenderer implements Disposable{
|
|||||||
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
int idxWall = (wx % chunksize) + (wy % chunksize) * chunksize;
|
||||||
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
|
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
|
||||||
|
|
||||||
if(wall != Blocks.air && (wall.synthetic() || wall == Blocks.part)){
|
if(wall != Blocks.air && (wall.synthetic() || wall instanceof BlockPart)){
|
||||||
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||||
|
|
||||||
if(wall.rotate){
|
if(wall.rotate){
|
||||||
mesh.draw(idxWall, region,
|
mesh.draw(idxWall, region,
|
||||||
wx * tilesize + wall.offset(), wy * tilesize + wall.offset(),
|
wx * tilesize + wall.offset(), wy * tilesize + wall.offset(),
|
||||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, tile.getRotation() * 90 - 90);
|
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl, tile.rotation() * 90 - 90);
|
||||||
}else{
|
}else{
|
||||||
mesh.draw(idxWall, region,
|
mesh.draw(idxWall, region,
|
||||||
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl) / 2f,
|
wx * tilesize + wall.offset() + (tilesize - region.getWidth() * Draw.scl) / 2f,
|
||||||
|
|||||||
@@ -85,9 +85,8 @@ public class Damage{
|
|||||||
public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length){
|
public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length){
|
||||||
tr.trns(angle, length);
|
tr.trns(angle, length);
|
||||||
world.raycastEachWorld(x, y, x + tr.x, y + tr.y, (cx, cy) -> {
|
world.raycastEachWorld(x, y, x + tr.x, y + tr.y, (cx, cy) -> {
|
||||||
Tile tile = world.tile(cx, cy);
|
Tile tile = world.ltile(cx, cy);
|
||||||
if(tile != null) tile = tile.target();
|
if(tile != null && tile.entity != null && tile.getTeamID() != team.ordinal() && tile.entity.collide(hitter)){
|
||||||
if(tile != null && tile.entity != null && tile.target().getTeamID() != team.ordinal() && tile.entity.collide(hitter)){
|
|
||||||
tile.entity.collision(hitter);
|
tile.entity.collision(hitter);
|
||||||
hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy());
|
hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy());
|
||||||
}
|
}
|
||||||
@@ -216,12 +215,10 @@ public class Damage{
|
|||||||
int scaledDamage = (int)(damage * (1f - (float)dst / radius));
|
int scaledDamage = (int)(damage * (1f - (float)dst / radius));
|
||||||
|
|
||||||
bits.set(bitOffset + x, bitOffset + y);
|
bits.set(bitOffset + x, bitOffset + y);
|
||||||
Tile tile = world.tile(startx + x, starty + y);
|
Tile tile = world.ltile(startx + x, starty + y);
|
||||||
|
|
||||||
if(scaledDamage <= 0 || tile == null) continue;
|
if(scaledDamage <= 0 || tile == null) continue;
|
||||||
|
|
||||||
tile = tile.target();
|
|
||||||
|
|
||||||
//apply damage to entity if needed
|
//apply damage to entity if needed
|
||||||
if(tile.entity != null && tile.getTeam() != team){
|
if(tile.entity != null && tile.getTeam() != team){
|
||||||
int health = (int)tile.entity.health;
|
int health = (int)tile.entity.health;
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ import io.anuke.arc.function.Consumer;
|
|||||||
import io.anuke.arc.function.Predicate;
|
import io.anuke.arc.function.Predicate;
|
||||||
import io.anuke.arc.graphics.Camera;
|
import io.anuke.arc.graphics.Camera;
|
||||||
import io.anuke.arc.math.geom.Rectangle;
|
import io.anuke.arc.math.geom.Rectangle;
|
||||||
import io.anuke.mindustry.Vars;
|
|
||||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||||
import io.anuke.mindustry.entities.traits.Entity;
|
import io.anuke.mindustry.entities.traits.Entity;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.collisions;
|
||||||
|
|
||||||
public class Entities{
|
public class Entities{
|
||||||
public static final int maxLeafObjects = 4;
|
public static final int maxLeafObjects = 4;
|
||||||
private static final Array<EntityGroup<?>> groupArray = new Array<>();
|
private static final Array<EntityGroup<?>> groupArray = new Array<>();
|
||||||
@@ -48,7 +49,7 @@ public class Entities{
|
|||||||
group.updateEvents();
|
group.updateEvents();
|
||||||
|
|
||||||
if(group.useTree()){
|
if(group.useTree()){
|
||||||
Vars.collisions.updatePhysics(group);
|
collisions.updatePhysics(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Entity e : group.all()){
|
for(Entity e : group.all()){
|
||||||
|
|||||||
@@ -225,9 +225,8 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool
|
|||||||
if(type.hitTiles && collidesTiles() && !supressCollision && initialized){
|
if(type.hitTiles && collidesTiles() && !supressCollision && initialized){
|
||||||
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
|
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
|
||||||
|
|
||||||
Tile tile = world.tile(x, y);
|
Tile tile = world.ltile(x, y);
|
||||||
if(tile == null) return false;
|
if(tile == null) return false;
|
||||||
tile = tile.target();
|
|
||||||
|
|
||||||
if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != team)){
|
if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != team)){
|
||||||
if(tile.getTeam() != team){
|
if(tile.getTeam() != team){
|
||||||
|
|||||||
@@ -72,6 +72,11 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte version(){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float lifetime(){
|
public float lifetime(){
|
||||||
return lifetime;
|
return lifetime;
|
||||||
@@ -98,7 +103,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TileEntity entity = tile.target().entity;
|
TileEntity entity = tile.link().entity;
|
||||||
boolean damage = entity != null;
|
boolean damage = entity != null;
|
||||||
|
|
||||||
float flammability = baseFlammability + puddleFlammability;
|
float flammability = baseFlammability + puddleFlammability;
|
||||||
@@ -151,7 +156,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
this.loadedPosition = stream.readInt();
|
this.loadedPosition = stream.readInt();
|
||||||
this.lifetime = stream.readFloat();
|
this.lifetime = stream.readFloat();
|
||||||
this.time = stream.readFloat();
|
this.time = stream.readFloat();
|
||||||
|
|||||||
@@ -143,6 +143,11 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
|||||||
return liquid.flammability * amount;
|
return liquid.flammability * amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte version(){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hitbox(Rectangle rectangle){
|
public void hitbox(Rectangle rectangle){
|
||||||
rectangle.setCenter(x, y).setSize(tilesize);
|
rectangle.setCenter(x, y).setSize(tilesize);
|
||||||
@@ -201,7 +206,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(liquid.temperature > 0.7f && (tile.target().entity != null) && Mathf.chance(0.3 * Time.delta())){
|
if(liquid.temperature > 0.7f && (tile.link().entity != null) && Mathf.chance(0.3 * Time.delta())){
|
||||||
Fire.create(tile);
|
Fire.create(tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,7 +250,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
this.loadedPosition = stream.readInt();
|
this.loadedPosition = stream.readInt();
|
||||||
this.x = stream.readFloat();
|
this.x = stream.readFloat();
|
||||||
this.y = stream.readFloat();
|
this.y = stream.readFloat();
|
||||||
|
|||||||
@@ -40,10 +40,98 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
|||||||
float placeDistance = 220f;
|
float placeDistance = 220f;
|
||||||
float mineDistance = 70f;
|
float mineDistance = 70f;
|
||||||
|
|
||||||
//due to iOS wierdness
|
/**
|
||||||
class BuildDataStatic{
|
* Update building mechanism for this unit.
|
||||||
static Array<BuildRequest> removal = new Array<>();
|
* This includes mining.
|
||||||
static Vector2[] tmptr = new Vector2[]{new Vector2(), new Vector2(), new Vector2(), new Vector2()};
|
*/
|
||||||
|
default void updateBuilding(){
|
||||||
|
float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : placeDistance;
|
||||||
|
Unit unit = (Unit)this;
|
||||||
|
//remove already completed build requests
|
||||||
|
removal.clear();
|
||||||
|
for(BuildRequest req : getPlaceQueue()){
|
||||||
|
removal.add(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlaceQueue().clear();
|
||||||
|
|
||||||
|
for(BuildRequest request : removal){
|
||||||
|
if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) ||
|
||||||
|
(!request.breaking && (world.tile(request.x, request.y).rotation() == request.rotation || !request.block.rotate)
|
||||||
|
&& world.tile(request.x, request.y).block() == request.block))){
|
||||||
|
getPlaceQueue().addLast(request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildRequest current = getCurrentRequest();
|
||||||
|
|
||||||
|
//update mining here
|
||||||
|
if(current == null){
|
||||||
|
if(getMineTile() != null){
|
||||||
|
updateMining();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
setMineTile(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tile tile = world.tile(current.x, current.y);
|
||||||
|
|
||||||
|
if(dst(tile) > finalPlaceDst){
|
||||||
|
if(getPlaceQueue().size > 1){
|
||||||
|
getPlaceQueue().removeFirst();
|
||||||
|
getPlaceQueue().addLast(current);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(tile.block() instanceof BuildBlock)){
|
||||||
|
if(canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){
|
||||||
|
Call.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
|
||||||
|
}else if(canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){
|
||||||
|
Call.beginBreak(getTeam(), current.x, current.y);
|
||||||
|
}else{
|
||||||
|
getPlaceQueue().removeFirst();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TileEntity core = unit.getClosestCore();
|
||||||
|
|
||||||
|
//if there is no core to build with or no build entity, stop building!
|
||||||
|
if((core == null && !state.rules.infiniteResources) || !(tile.entity instanceof BuildEntity)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//otherwise, update it.
|
||||||
|
BuildEntity entity = tile.entity();
|
||||||
|
|
||||||
|
if(entity == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(unit.dst(tile) <= finalPlaceDst){
|
||||||
|
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f);
|
||||||
|
}
|
||||||
|
|
||||||
|
//progress is synced, thus not updated clientside
|
||||||
|
if(!Net.client()){
|
||||||
|
//deconstructing is 2x as fast
|
||||||
|
if(current.breaking){
|
||||||
|
entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
|
||||||
|
}else{
|
||||||
|
entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
current.progress = entity.progress();
|
||||||
|
}else{
|
||||||
|
entity.progress = current.progress;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!current.initialized){
|
||||||
|
Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, unit.getTeam(), this, current.breaking)));
|
||||||
|
current.initialized = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the queue for storing build requests. */
|
/** Returns the queue for storing build requests. */
|
||||||
@@ -148,97 +236,10 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
|||||||
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
|
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
//due to iOS wierdness, this is apparently required
|
||||||
* Update building mechanism for this unit.
|
class BuildDataStatic{
|
||||||
* This includes mining.
|
static Array<BuildRequest> removal = new Array<>();
|
||||||
*/
|
static Vector2[] tmptr = new Vector2[]{new Vector2(), new Vector2(), new Vector2(), new Vector2()};
|
||||||
default void updateBuilding(){
|
|
||||||
Unit unit = (Unit)this;
|
|
||||||
//remove already completed build requests
|
|
||||||
removal.clear();
|
|
||||||
for(BuildRequest req : getPlaceQueue()){
|
|
||||||
removal.add(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlaceQueue().clear();
|
|
||||||
|
|
||||||
for(BuildRequest request : removal){
|
|
||||||
if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) ||
|
|
||||||
(!request.breaking && (world.tile(request.x, request.y).getRotation() == request.rotation || !request.block.rotate)
|
|
||||||
&& world.tile(request.x, request.y).block() == request.block))){
|
|
||||||
getPlaceQueue().addLast(request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BuildRequest current = getCurrentRequest();
|
|
||||||
|
|
||||||
//update mining here
|
|
||||||
if(current == null){
|
|
||||||
if(getMineTile() != null){
|
|
||||||
updateMining();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}else{
|
|
||||||
setMineTile(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
Tile tile = world.tile(current.x, current.y);
|
|
||||||
|
|
||||||
if(dst(tile) > placeDistance){
|
|
||||||
if(getPlaceQueue().size > 1){
|
|
||||||
getPlaceQueue().removeFirst();
|
|
||||||
getPlaceQueue().addLast(current);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!(tile.block() instanceof BuildBlock)){
|
|
||||||
if(canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){
|
|
||||||
Call.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
|
|
||||||
}else if(canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){
|
|
||||||
Call.beginBreak(getTeam(), current.x, current.y);
|
|
||||||
}else{
|
|
||||||
getPlaceQueue().removeFirst();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TileEntity core = unit.getClosestCore();
|
|
||||||
|
|
||||||
//if there is no core to build with or no build entity, stop building!
|
|
||||||
if(core == null || !(tile.entity instanceof BuildEntity)){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//otherwise, update it.
|
|
||||||
BuildEntity entity = tile.entity();
|
|
||||||
|
|
||||||
if(entity == null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(unit.dst(tile) <= placeDistance){
|
|
||||||
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f);
|
|
||||||
}
|
|
||||||
|
|
||||||
//progress is synced, thus not updated clientside
|
|
||||||
if(!Net.client()){
|
|
||||||
//deconstructing is 2x as fast
|
|
||||||
if(current.breaking){
|
|
||||||
entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
|
|
||||||
}else{
|
|
||||||
entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
|
|
||||||
}
|
|
||||||
|
|
||||||
current.progress = entity.progress();
|
|
||||||
}else{
|
|
||||||
entity.progress = current.progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!current.initialized){
|
|
||||||
Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, unit.getTeam(), this, current.breaking)));
|
|
||||||
current.initialized = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Do not call directly. */
|
/** Do not call directly. */
|
||||||
@@ -291,7 +292,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
|||||||
|
|
||||||
Tile tile = world.tile(request.x, request.y);
|
Tile tile = world.tile(request.x, request.y);
|
||||||
|
|
||||||
if(dst(tile) > placeDistance){
|
if(dst(tile) > placeDistance && !state.isEditor()){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ package io.anuke.mindustry.entities.traits;
|
|||||||
* Marks an entity as serializable.
|
* Marks an entity as serializable.
|
||||||
*/
|
*/
|
||||||
public interface SaveTrait extends Entity, TypeTrait, Saveable{
|
public interface SaveTrait extends Entity, TypeTrait, Saveable{
|
||||||
|
byte version();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,5 @@ import java.io.*;
|
|||||||
|
|
||||||
public interface Saveable{
|
public interface Saveable{
|
||||||
void writeSave(DataOutput stream) throws IOException;
|
void writeSave(DataOutput stream) throws IOException;
|
||||||
|
void readSave(DataInput stream, byte version) throws IOException;
|
||||||
void readSave(DataInput stream) throws IOException;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,15 +41,6 @@ public interface SyncTrait extends Entity, TypeTrait{
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether this entity is clipped and not synced when out of viewport. */
|
|
||||||
default boolean isClipped(){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default float clipSize(){
|
|
||||||
return (this instanceof DrawTrait ? ((DrawTrait)this).drawSize() : 8f);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Read and write sync data, usually position
|
//Read and write sync data, usually position
|
||||||
void write(DataOutput data) throws IOException;
|
void write(DataOutput data) throws IOException;
|
||||||
|
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ public interface TypeTrait{
|
|||||||
lastRegisteredID[0]++;
|
lastRegisteredID[0]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**Gets a syncable type by ID.*/
|
||||||
* Registers a syncable type by ID.
|
|
||||||
*/
|
|
||||||
static Supplier<? extends TypeTrait> getTypeByID(int id){
|
static Supplier<? extends TypeTrait> getTypeByID(int id){
|
||||||
if(id == -1){
|
if(id == -1){
|
||||||
throw new IllegalArgumentException("Attempt to retrieve invalid entity type ID! Did you forget to set it in ContentLoader.registerTypes()?");
|
throw new IllegalArgumentException("Attempt to retrieve invalid entity type ID! Did you forget to set it in ContentLoader.registerTypes()?");
|
||||||
|
|||||||
@@ -244,12 +244,14 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void update(){
|
||||||
hitTime -= Time.delta();
|
|
||||||
|
|
||||||
if(isDead()){
|
if(isDead()){
|
||||||
|
//dead enemies should get immediately removed
|
||||||
|
remove();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hitTime -= Time.delta();
|
||||||
|
|
||||||
if(Net.client()){
|
if(Net.client()){
|
||||||
interpolate();
|
interpolate();
|
||||||
status.update(this);
|
status.update(this);
|
||||||
@@ -304,11 +306,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
return type.hitsize * 10;
|
return type.hitsize * 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public float clipSize(){
|
|
||||||
return isBoss() ? 10000000000f : super.clipSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDeath(){
|
public void onDeath(){
|
||||||
Call.onUnitDeath(this);
|
Call.onUnitDeath(this);
|
||||||
@@ -336,6 +333,11 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
return unitGroups[team.ordinal()];
|
return unitGroups[team.ordinal()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte version(){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSave(DataOutput stream) throws IOException{
|
public void writeSave(DataOutput stream) throws IOException{
|
||||||
super.writeSave(stream);
|
super.writeSave(stream);
|
||||||
@@ -344,8 +346,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
super.readSave(stream);
|
super.readSave(stream, version);
|
||||||
byte type = stream.readByte();
|
byte type = stream.readByte();
|
||||||
this.spawner = stream.readInt();
|
this.spawner = stream.readInt();
|
||||||
|
|
||||||
@@ -363,7 +365,9 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
@Override
|
@Override
|
||||||
public void read(DataInput data) throws IOException{
|
public void read(DataInput data) throws IOException{
|
||||||
float lastx = x, lasty = y, lastrot = rotation;
|
float lastx = x, lasty = y, lastrot = rotation;
|
||||||
super.readSave(data);
|
|
||||||
|
super.readSave(data, version());
|
||||||
|
|
||||||
this.type = content.getByID(ContentType.unit, data.readByte());
|
this.type = content.getByID(ContentType.unit, data.readByte());
|
||||||
this.spawner = data.readInt();
|
this.spawner = data.readInt();
|
||||||
|
|
||||||
|
|||||||
@@ -432,7 +432,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
if(getCurrentRequest() == request && request.progress > 0.001f) continue;
|
if(getCurrentRequest() == request && request.progress > 0.001f) continue;
|
||||||
|
|
||||||
if(request.breaking){
|
if(request.breaking){
|
||||||
Block block = world.tile(request.x, request.y).target().block();
|
Block block = world.ltile(request.x, request.y).block();
|
||||||
|
|
||||||
//draw removal request
|
//draw removal request
|
||||||
Lines.stroke(2f, Pal.removeBack);
|
Lines.stroke(2f, Pal.removeBack);
|
||||||
@@ -636,13 +636,22 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void updateShooting(){
|
protected void updateShooting(){
|
||||||
if(isShooting() && mech.canShoot(this)){
|
if(!state.isEditor() && isShooting() && mech.canShoot(this)){
|
||||||
mech.weapon.update(this, pointerX, pointerY);
|
if(!mech.turnCursor){
|
||||||
|
//shoot forward ignoring cursor
|
||||||
|
mech.weapon.update(this, x + Angles.trnsx(rotation, 1f), y + Angles.trnsy(rotation, 1f));
|
||||||
|
}else{
|
||||||
|
mech.weapon.update(this, pointerX, pointerY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void updateFlying(){
|
protected void updateFlying(){
|
||||||
if(Units.invalidateTarget(target, this) && !(target instanceof TileEntity && ((TileEntity)target).damaged() && target.isValid() && ((TileEntity)target).isAdded() && target.getTeam() == team && mech.canHeal && dst(target) < getWeapon().bullet.range())){
|
if(Units.invalidateTarget(target, this) && !(target instanceof TileEntity && ((TileEntity)target).damaged() && target.isValid() && target.getTeam() == team && mech.canHeal && dst(target) < getWeapon().bullet.range())){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state.isEditor()){
|
||||||
target = null;
|
target = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,6 +787,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
moveTarget = null;
|
moveTarget = null;
|
||||||
spawner = lastSpawner = null;
|
spawner = lastSpawner = null;
|
||||||
health = maxHealth();
|
health = maxHealth();
|
||||||
|
mining = null;
|
||||||
boostHeat = drownTime = hitTime = 0f;
|
boostHeat = drownTime = hitTime = 0f;
|
||||||
mech = Mechs.starter;
|
mech = Mechs.starter;
|
||||||
placeQueue.clear();
|
placeQueue.clear();
|
||||||
@@ -790,7 +800,11 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
|
|
||||||
public void updateRespawning(){
|
public void updateRespawning(){
|
||||||
|
|
||||||
if(spawner != null && spawner.isValid()){
|
if(state.isEditor()){
|
||||||
|
//instant respawn at center of map.
|
||||||
|
set(world.width() * tilesize/2f, world.height() * tilesize/2f);
|
||||||
|
setDead(false);
|
||||||
|
}else if(spawner != null && spawner.isValid()){
|
||||||
spawner.updateSpawning(this);
|
spawner.updateSpawning(this);
|
||||||
}else if(!netServer.isWaitingForPlayers()){
|
}else if(!netServer.isWaitingForPlayers()){
|
||||||
if(!Net.client()){
|
if(!Net.client()){
|
||||||
@@ -810,6 +824,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
this.lastSpawner = spawner;
|
this.lastSpawner = spawner;
|
||||||
this.dead = true;
|
this.dead = true;
|
||||||
setNet(spawner.getX(), spawner.getY());
|
setNet(spawner.getX(), spawner.getY());
|
||||||
|
spawner.updateSpawning(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
@@ -817,8 +832,8 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
//region read and write methods
|
//region read and write methods
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isClipped(){
|
public byte version(){
|
||||||
return false;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -833,7 +848,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
boolean local = stream.readBoolean();
|
boolean local = stream.readBoolean();
|
||||||
|
|
||||||
if(local){
|
if(local){
|
||||||
@@ -844,14 +859,14 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
lastSpawner = (SpawnerTrait)stile.entity;
|
lastSpawner = (SpawnerTrait)stile.entity;
|
||||||
}
|
}
|
||||||
Player player = headless ? this : Vars.player;
|
Player player = headless ? this : Vars.player;
|
||||||
player.readSaveSuper(stream);
|
player.readSaveSuper(stream, version);
|
||||||
player.mech = content.getByID(ContentType.mech, mechid);
|
player.mech = content.getByID(ContentType.mech, mechid);
|
||||||
player.dead = false;
|
player.dead = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readSaveSuper(DataInput stream) throws IOException{
|
private void readSaveSuper(DataInput stream, byte version) throws IOException{
|
||||||
super.readSave(stream);
|
super.readSave(stream, version);
|
||||||
|
|
||||||
add();
|
add();
|
||||||
}
|
}
|
||||||
@@ -859,7 +874,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
@Override
|
@Override
|
||||||
public void write(DataOutput buffer) throws IOException{
|
public void write(DataOutput buffer) throws IOException{
|
||||||
super.writeSave(buffer, !isLocal);
|
super.writeSave(buffer, !isLocal);
|
||||||
TypeIO.writeStringData(buffer, name); //TODO writing strings is very inefficient
|
TypeIO.writeStringData(buffer, name);
|
||||||
buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3));
|
buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3));
|
||||||
buffer.writeInt(Color.rgba8888(color));
|
buffer.writeInt(Color.rgba8888(color));
|
||||||
buffer.writeByte(mech.id);
|
buffer.writeByte(mech.id);
|
||||||
@@ -873,7 +888,9 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
|||||||
@Override
|
@Override
|
||||||
public void read(DataInput buffer) throws IOException{
|
public void read(DataInput buffer) throws IOException{
|
||||||
float lastx = x, lasty = y, lastrot = rotation, lastvx = velocity.x, lastvy = velocity.y;
|
float lastx = x, lasty = y, lastrot = rotation, lastvx = velocity.x, lastvy = velocity.y;
|
||||||
super.readSave(buffer);
|
|
||||||
|
super.readSave(buffer, version());
|
||||||
|
|
||||||
name = TypeIO.readStringData(buffer);
|
name = TypeIO.readStringData(buffer);
|
||||||
byte bools = buffer.readByte();
|
byte bools = buffer.readByte();
|
||||||
isAdmin = (bools & 1) != 0;
|
isAdmin = (bools & 1) != 0;
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
package io.anuke.mindustry.entities.type;
|
package io.anuke.mindustry.entities.type;
|
||||||
|
|
||||||
import io.anuke.annotations.Annotations.Loc;
|
import io.anuke.annotations.Annotations.*;
|
||||||
import io.anuke.annotations.Annotations.Remote;
|
|
||||||
import io.anuke.arc.Events;
|
import io.anuke.arc.Events;
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
import io.anuke.arc.collection.ObjectSet;
|
import io.anuke.arc.collection.ObjectSet;
|
||||||
import io.anuke.arc.math.geom.Point2;
|
import io.anuke.arc.math.geom.Point2;
|
||||||
import io.anuke.arc.math.geom.Vector2;
|
import io.anuke.arc.math.geom.Vector2;
|
||||||
import io.anuke.arc.util.Interval;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.Time;
|
|
||||||
import io.anuke.mindustry.entities.EntityGroup;
|
import io.anuke.mindustry.entities.EntityGroup;
|
||||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||||
import io.anuke.mindustry.entities.impl.BaseEntity;
|
import io.anuke.mindustry.entities.impl.BaseEntity;
|
||||||
@@ -115,16 +113,35 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
return dead || tile.entity != this;
|
return dead || tile.entity != this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@CallSuper
|
||||||
public void write(DataOutput stream) throws IOException{
|
public void write(DataOutput stream) throws IOException{
|
||||||
|
stream.writeShort((short)health);
|
||||||
|
stream.writeByte(Pack.byteByte(tile.getTeamID(), tile.rotation())); //team + rotation
|
||||||
|
if(items != null) items.write(stream);
|
||||||
|
if(power != null) power.write(stream);
|
||||||
|
if(liquids != null) liquids.write(stream);
|
||||||
|
if(cons != null) cons.write(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeConfig(DataOutput stream) throws IOException{
|
@CallSuper
|
||||||
|
public void read(DataInput stream, byte revision) throws IOException{
|
||||||
|
health = stream.readUnsignedShort();
|
||||||
|
byte tr = stream.readByte();
|
||||||
|
byte team = Pack.leftByte(tr);
|
||||||
|
byte rotation = Pack.rightByte(tr);
|
||||||
|
|
||||||
|
tile.setTeam(Team.all[team]);
|
||||||
|
tile.rotation(rotation);
|
||||||
|
|
||||||
|
if(items != null) items.read(stream);
|
||||||
|
if(power != null) power.read(stream);
|
||||||
|
if(liquids != null) liquids.read(stream);
|
||||||
|
if(cons != null) cons.read(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void read(DataInput stream) throws IOException{
|
/** Returns the version of this TileEntity IO code.*/
|
||||||
}
|
public byte version(){
|
||||||
|
return 0;
|
||||||
public void readConfig(DataInput stream) throws IOException{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean collide(Bullet other){
|
public boolean collide(Bullet other){
|
||||||
@@ -168,14 +185,14 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
|
|
||||||
Point2[] nearby = Edges.getEdges(block.size);
|
Point2[] nearby = Edges.getEdges(block.size);
|
||||||
for(Point2 point : nearby){
|
for(Point2 point : nearby){
|
||||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
Tile other = world.ltile(tile.x + point.x, tile.y + point.y);
|
||||||
//remove this tile from all nearby tile's proximities
|
//remove this tile from all nearby tile's proximities
|
||||||
if(other != null){
|
if(other != null){
|
||||||
other = other.target();
|
|
||||||
other.block().onProximityUpdate(other);
|
other.block().onProximityUpdate(other);
|
||||||
}
|
|
||||||
if(other != null && other.entity != null){
|
if(other.entity != null){
|
||||||
other.entity.proximity.removeValue(tile, true);
|
other.entity.proximity.removeValue(tile, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,10 +203,9 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
|
|
||||||
Point2[] nearby = Edges.getEdges(block.size);
|
Point2[] nearby = Edges.getEdges(block.size);
|
||||||
for(Point2 point : nearby){
|
for(Point2 point : nearby){
|
||||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
Tile other = world.ltile(tile.x + point.x, tile.y + point.y);
|
||||||
|
|
||||||
if(other == null) continue;
|
if(other == null) continue;
|
||||||
other = other.target();
|
|
||||||
if(other.entity == null || !(other.interactable(tile.getTeam()))) continue;
|
if(other.entity == null || !(other.interactable(tile.getTeam()))) continue;
|
||||||
|
|
||||||
other.block().onProximityUpdate(other);
|
other.block().onProximityUpdate(other);
|
||||||
@@ -280,6 +296,11 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(){
|
||||||
|
return !isDead() && tile.entity == this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityGroup targetGroup(){
|
public EntityGroup targetGroup(){
|
||||||
return tileGroup;
|
return tileGroup;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.anuke.mindustry.entities.type;
|
package io.anuke.mindustry.entities.type;
|
||||||
|
|
||||||
|
import io.anuke.annotations.Annotations.Nullable;
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.Events;
|
import io.anuke.arc.Events;
|
||||||
import io.anuke.arc.graphics.Color;
|
import io.anuke.arc.graphics.Color;
|
||||||
@@ -8,7 +9,8 @@ import io.anuke.arc.graphics.g2d.TextureRegion;
|
|||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.math.geom.Geometry;
|
import io.anuke.arc.math.geom.Geometry;
|
||||||
import io.anuke.arc.math.geom.Vector2;
|
import io.anuke.arc.math.geom.Vector2;
|
||||||
import io.anuke.arc.util.*;
|
import io.anuke.arc.util.Time;
|
||||||
|
import io.anuke.arc.util.Tmp;
|
||||||
import io.anuke.mindustry.content.Blocks;
|
import io.anuke.mindustry.content.Blocks;
|
||||||
import io.anuke.mindustry.content.Fx;
|
import io.anuke.mindustry.content.Fx;
|
||||||
import io.anuke.mindustry.entities.*;
|
import io.anuke.mindustry.entities.*;
|
||||||
@@ -138,7 +140,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
byte team = stream.readByte();
|
byte team = stream.readByte();
|
||||||
boolean dead = stream.readBoolean();
|
boolean dead = stream.readBoolean();
|
||||||
float x = stream.readFloat();
|
float x = stream.readFloat();
|
||||||
@@ -150,7 +152,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
byte itemID = stream.readByte();
|
byte itemID = stream.readByte();
|
||||||
short itemAmount = stream.readShort();
|
short itemAmount = stream.readShort();
|
||||||
|
|
||||||
this.status.readSave(stream);
|
this.status.readSave(stream, version);
|
||||||
this.item.amount = itemAmount;
|
this.item.amount = itemAmount;
|
||||||
this.item.item = content.item(itemID);
|
this.item.item = content.item(itemID);
|
||||||
this.dead = dead;
|
this.dead = dead;
|
||||||
@@ -221,7 +223,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
velocity.add(moveVector.x / mass() * Time.delta(), moveVector.y / mass() * Time.delta());
|
velocity.add(moveVector.x / mass() * Time.delta(), moveVector.y / mass() * Time.delta());
|
||||||
}
|
}
|
||||||
|
|
||||||
public TileEntity getClosestCore(){
|
public @Nullable TileEntity getClosestCore(){
|
||||||
TeamData data = state.teams.get(team);
|
TeamData data = state.teams.get(team);
|
||||||
|
|
||||||
Tile tile = Geometry.findClosest(x, y, data.cores);
|
Tile tile = Geometry.findClosest(x, y, data.cores);
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
|||||||
if(isBreaking){
|
if(isBreaking){
|
||||||
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
|
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
|
||||||
}else{
|
}else{
|
||||||
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.getRotation(), entity.cblock));
|
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,7 +211,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
|||||||
Events.on(BuildSelectEvent.class, event -> {
|
Events.on(BuildSelectEvent.class, event -> {
|
||||||
EntityGroup<BaseUnit> group = unitGroups[event.team.ordinal()];
|
EntityGroup<BaseUnit> group = unitGroups[event.team.ordinal()];
|
||||||
|
|
||||||
if(!(event.builder instanceof Player) || !(event.tile.entity instanceof BuildEntity)) return;
|
if(!(event.tile.entity instanceof BuildEntity)) return;
|
||||||
|
|
||||||
for(BaseUnit unit : group.all()){
|
for(BaseUnit unit : group.all()){
|
||||||
if(unit instanceof Drone){
|
if(unit instanceof Drone){
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ public class Statuses implements Saveable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readSave(DataInput stream) throws IOException{
|
public void readSave(DataInput stream, byte version) throws IOException{
|
||||||
for(StatusEntry effect : statuses){
|
for(StatusEntry effect : statuses){
|
||||||
Pools.free(effect);
|
Pools.free(effect);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import io.anuke.mindustry.type.ContentType;
|
|||||||
|
|
||||||
/** Base class for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. */
|
/** Base class for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. */
|
||||||
public abstract class Content{
|
public abstract class Content{
|
||||||
public final byte id;
|
public final short id;
|
||||||
|
|
||||||
public Content(){
|
public Content(){
|
||||||
this.id = (byte)Vars.content.getBy(getContentType()).size;
|
this.id = (short)Vars.content.getBy(getContentType()).size;
|
||||||
Vars.content.handleContent(this);
|
Vars.content.handleContent(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,64 @@
|
|||||||
package io.anuke.mindustry.game;
|
package io.anuke.mindustry.game;
|
||||||
|
|
||||||
import io.anuke.arc.Core;
|
import io.anuke.arc.Core;
|
||||||
import io.anuke.arc.function.Supplier;
|
import io.anuke.arc.function.Consumer;
|
||||||
|
|
||||||
/** Defines preset rule sets.. */
|
/** Defines preset rule sets.. */
|
||||||
public enum Gamemode{
|
public enum Gamemode{
|
||||||
survival(() -> new Rules(){{
|
survival(rules -> {
|
||||||
waveTimer = true;
|
rules.waveTimer = true;
|
||||||
waves = true;
|
rules.waves = true;
|
||||||
unitDrops = true;
|
rules.unitDrops = true;
|
||||||
spawns = DefaultWaves.get();
|
}),
|
||||||
}}),
|
sandbox(rules -> {
|
||||||
sandbox(() -> new Rules(){{
|
rules.infiniteResources = true;
|
||||||
infiniteResources = true;
|
rules.waves = true;
|
||||||
waves = true;
|
rules.waveTimer = false;
|
||||||
waveTimer = false;
|
rules.respawnTime = 0f;
|
||||||
respawnTime = 0f;
|
}),
|
||||||
}}),
|
attack(rules -> {
|
||||||
attack(() -> new Rules(){{
|
rules.enemyCheat = true;
|
||||||
enemyCheat = true;
|
rules.unitDrops = true;
|
||||||
unitDrops = true;
|
rules.waves = false;
|
||||||
waves = false;
|
rules.attackMode = true;
|
||||||
attackMode = true;
|
}),
|
||||||
}}),
|
pvp(rules -> {
|
||||||
pvp(() -> new Rules(){{
|
rules.pvp = true;
|
||||||
pvp = true;
|
rules.enemyCoreBuildRadius = 600f;
|
||||||
enemyCoreBuildRadius = 600f;
|
rules.respawnTime = 60 * 10;
|
||||||
respawnTime = 60 * 10;
|
rules.buildCostMultiplier = 0.5f;
|
||||||
buildCostMultiplier = 0.5f;
|
rules.buildSpeedMultiplier = 2f;
|
||||||
buildSpeedMultiplier = 2f;
|
rules.playerDamageMultiplier = 0.45f;
|
||||||
playerDamageMultiplier = 0.45f;
|
rules.playerHealthMultiplier = 0.8f;
|
||||||
playerHealthMultiplier = 0.8f;
|
rules.unitBuildSpeedMultiplier = 3f;
|
||||||
unitBuildSpeedMultiplier = 3f;
|
rules.unitHealthMultiplier = 2f;
|
||||||
unitHealthMultiplier = 2f;
|
rules.attackMode = true;
|
||||||
attackMode = true;
|
}),
|
||||||
}});
|
editor(true, rules -> {
|
||||||
|
rules.infiniteResources = true;
|
||||||
|
rules.editor = true;
|
||||||
|
rules.waves = false;
|
||||||
|
rules.enemyCoreBuildRadius = 0f;
|
||||||
|
rules.waveTimer = false;
|
||||||
|
rules.respawnTime = 0f;
|
||||||
|
});
|
||||||
|
|
||||||
private final Supplier<Rules> rules;
|
private final Consumer<Rules> rules;
|
||||||
|
public final boolean hidden;
|
||||||
|
|
||||||
Gamemode(Supplier<Rules> rules){
|
Gamemode(Consumer<Rules> rules){
|
||||||
this.rules = rules;
|
this(false, rules);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rules get(){
|
Gamemode(boolean hidden, Consumer<Rules> rules){
|
||||||
return rules.get();
|
this.rules = rules;
|
||||||
|
this.hidden = hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Applies this preset to this ruleset. */
|
||||||
|
public Rules apply(Rules in){
|
||||||
|
rules.accept(in);
|
||||||
|
return in;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String description(){
|
public String description(){
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package io.anuke.mindustry.game;
|
|||||||
|
|
||||||
import io.anuke.annotations.Annotations.Serialize;
|
import io.anuke.annotations.Annotations.Serialize;
|
||||||
import io.anuke.arc.collection.Array;
|
import io.anuke.arc.collection.Array;
|
||||||
|
import io.anuke.mindustry.io.JsonIO;
|
||||||
|
import io.anuke.mindustry.type.Zone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines current rules on how the game should function.
|
* Defines current rules on how the game should function.
|
||||||
@@ -47,10 +49,10 @@ public class Rules{
|
|||||||
public float bossWaveMultiplier = 3f;
|
public float bossWaveMultiplier = 3f;
|
||||||
/** How many times longer a launch wave takes. */
|
/** How many times longer a launch wave takes. */
|
||||||
public float launchWaveMultiplier = 2f;
|
public float launchWaveMultiplier = 2f;
|
||||||
/** Zone ID, -1 for invalid zone. */
|
/** Zone for saves that have them.*/
|
||||||
public byte zone = -1;
|
public Zone zone;
|
||||||
/** Spawn layout. Should be assigned on save load based on map or zone. */
|
/** Spawn layout. Should be assigned on save load based on map or zone. */
|
||||||
public transient Array<SpawnGroup> spawns = DefaultWaves.get();
|
public Array<SpawnGroup> spawns = DefaultWaves.get();
|
||||||
/** Determines if there should be limited respawns. */
|
/** Determines if there should be limited respawns. */
|
||||||
public boolean limitedRespawns = false;
|
public boolean limitedRespawns = false;
|
||||||
/** How many times player can respawn during one wave. */
|
/** How many times player can respawn during one wave. */
|
||||||
@@ -59,4 +61,11 @@ public class Rules{
|
|||||||
public boolean waitForWaveToEnd = false;
|
public boolean waitForWaveToEnd = false;
|
||||||
/** Determinates if gamemode is attack mode */
|
/** Determinates if gamemode is attack mode */
|
||||||
public boolean attackMode = false;
|
public boolean attackMode = false;
|
||||||
|
/** Whether this is the editor gamemode. */
|
||||||
|
public boolean editor = false;
|
||||||
|
|
||||||
|
/** Copies this ruleset exactly. Not very efficient at all, do not use often. */
|
||||||
|
public Rules copy(){
|
||||||
|
return JsonIO.read(Rules.class, JsonIO.write(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,22 +4,21 @@ import io.anuke.arc.Core;
|
|||||||
import io.anuke.arc.Events;
|
import io.anuke.arc.Events;
|
||||||
import io.anuke.arc.collection.*;
|
import io.anuke.arc.collection.*;
|
||||||
import io.anuke.arc.files.FileHandle;
|
import io.anuke.arc.files.FileHandle;
|
||||||
import io.anuke.arc.util.Strings;
|
import io.anuke.arc.util.*;
|
||||||
import io.anuke.arc.util.Time;
|
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
||||||
import io.anuke.mindustry.io.SaveIO;
|
import io.anuke.mindustry.io.SaveIO;
|
||||||
import io.anuke.mindustry.io.SaveIO.SaveException;
|
import io.anuke.mindustry.io.SaveIO.SaveException;
|
||||||
import io.anuke.mindustry.io.SaveMeta;
|
import io.anuke.mindustry.io.SaveMeta;
|
||||||
import io.anuke.mindustry.maps.Map;
|
import io.anuke.mindustry.maps.Map;
|
||||||
import io.anuke.mindustry.type.ContentType;
|
|
||||||
import io.anuke.mindustry.type.Zone;
|
import io.anuke.mindustry.type.Zone;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.saveExtension;
|
||||||
|
import static io.anuke.mindustry.Vars.state;
|
||||||
|
|
||||||
public class Saves{
|
public class Saves{
|
||||||
private int nextSlot;
|
private int nextSlot;
|
||||||
@@ -52,7 +51,7 @@ public class Saves{
|
|||||||
SaveSlot slot = new SaveSlot(index);
|
SaveSlot slot = new SaveSlot(index);
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
saveMap.put(slot.index, slot);
|
saveMap.put(slot.index, slot);
|
||||||
slot.meta = SaveIO.getData(index);
|
slot.meta = SaveIO.getMeta(index);
|
||||||
nextSlot = Math.max(index + 1, nextSlot);
|
nextSlot = Math.max(index + 1, nextSlot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -134,7 +133,7 @@ public class Saves{
|
|||||||
slot.setName(file.nameWithoutExtension());
|
slot.setName(file.nameWithoutExtension());
|
||||||
saves.add(slot);
|
saves.add(slot);
|
||||||
saveMap.put(slot.index, slot);
|
saveMap.put(slot.index, slot);
|
||||||
slot.meta = SaveIO.getData(slot.index);
|
slot.meta = SaveIO.getMeta(slot.index);
|
||||||
current = slot;
|
current = slot;
|
||||||
saveSlots();
|
saveSlots();
|
||||||
return slot;
|
return slot;
|
||||||
@@ -172,7 +171,7 @@ public class Saves{
|
|||||||
public void load() throws SaveException{
|
public void load() throws SaveException{
|
||||||
try{
|
try{
|
||||||
SaveIO.loadFromSlot(index);
|
SaveIO.loadFromSlot(index);
|
||||||
meta = SaveIO.getData(index);
|
meta = SaveIO.getMeta(index);
|
||||||
current = this;
|
current = this;
|
||||||
totalPlaytime = meta.timePlayed;
|
totalPlaytime = meta.timePlayed;
|
||||||
}catch(Exception e){
|
}catch(Exception e){
|
||||||
@@ -186,7 +185,7 @@ public class Saves{
|
|||||||
totalPlaytime = time;
|
totalPlaytime = time;
|
||||||
|
|
||||||
SaveIO.saveToSlot(index);
|
SaveIO.saveToSlot(index);
|
||||||
meta = SaveIO.getData(index);
|
meta = SaveIO.getMeta(index);
|
||||||
if(!state.is(State.menu)){
|
if(!state.is(State.menu)){
|
||||||
current = this;
|
current = this;
|
||||||
}
|
}
|
||||||
@@ -224,7 +223,7 @@ public class Saves{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Zone getZone(){
|
public Zone getZone(){
|
||||||
return meta == null || meta.rules == null ? null : content.getByID(ContentType.zone, meta.rules.zone);
|
return meta == null || meta.rules == null ? null : meta.rules.zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getBuild(){
|
public int getBuild(){
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import io.anuke.mindustry.type.*;
|
|||||||
@Serialize
|
@Serialize
|
||||||
public class Stats{
|
public class Stats{
|
||||||
/** Items delivered to global resoure counter. Zones only. */
|
/** Items delivered to global resoure counter. Zones only. */
|
||||||
public ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
|
public transient ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
|
||||||
/** Enemy (red team) units destroyed. */
|
/** Enemy (red team) units destroyed. */
|
||||||
public int enemyUnitsDestroyed;
|
public int enemyUnitsDestroyed;
|
||||||
/** Total waves lasted. */
|
/** Total waves lasted. */
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public class BlockRenderer implements Disposable{
|
|||||||
for(int y = 0; y < world.height(); y++){
|
for(int y = 0; y < world.height(); y++){
|
||||||
Tile tile = world.rawTile(x, y);
|
Tile tile = world.rawTile(x, y);
|
||||||
int edgeBlend = 2;
|
int edgeBlend = 2;
|
||||||
float rot = tile.getRotation();
|
float rot = tile.rotation();
|
||||||
boolean fillable = (tile.block().solid && tile.block().fillsTile && !tile.block().synthetic());
|
boolean fillable = (tile.block().solid && tile.block().fillsTile && !tile.block().synthetic());
|
||||||
int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (world.width() - 1)), Math.abs(y - (world.height() - 1)))));
|
int edgeDst = Math.min(x, Math.min(y, Math.min(Math.abs(x - (world.width() - 1)), Math.abs(y - (world.height() - 1)))));
|
||||||
if(edgeDst <= edgeBlend){
|
if(edgeDst <= edgeBlend){
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ public class FloorRenderer implements Disposable{
|
|||||||
|
|
||||||
//loop through all layers, and add layer index if it exists
|
//loop through all layers, and add layer index if it exists
|
||||||
for(int i = 0; i < layers; i++){
|
for(int i = 0; i < layers; i++){
|
||||||
if(chunk.caches[i] != -1){
|
if(chunk.caches[i] != -1 && i != CacheLayer.walls.ordinal()){
|
||||||
drawnLayerSet.add(i);
|
drawnLayerSet.add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ public class MinimapRenderer implements Disposable{
|
|||||||
for(Unit unit : units){
|
for(Unit unit : units){
|
||||||
float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h;
|
float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h;
|
||||||
Draw.color(unit.getTeam().color);
|
Draw.color(unit.getTeam().color);
|
||||||
Fill.rect(x + rx, y + ry, baseSize / 2f, baseSize / 2f);
|
Fill.rect(x + rx, y + ry, io.anuke.arc.scene.ui.layout.Unit.dp.scl(baseSize / 2f), io.anuke.arc.scene.ui.layout.Unit.dp.scl(baseSize / 2f));
|
||||||
}
|
}
|
||||||
|
|
||||||
Draw.color();
|
Draw.color();
|
||||||
@@ -129,7 +129,7 @@ public class MinimapRenderer implements Disposable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int colorFor(Tile tile){
|
private int colorFor(Tile tile){
|
||||||
tile = tile.target();
|
tile = tile.link();
|
||||||
return MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.getTeam());
|
return MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.getTeam());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -97,11 +97,10 @@ public class OverlayRenderer{
|
|||||||
//draw selected block bars and info
|
//draw selected block bars and info
|
||||||
if(input.block == null && !Core.scene.hasMouse()){
|
if(input.block == null && !Core.scene.hasMouse()){
|
||||||
Vector2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
|
Vector2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
|
||||||
Tile tile = world.tileWorld(vec.x, vec.y);
|
Tile tile = world.ltileWorld(vec.x, vec.y);
|
||||||
|
|
||||||
if(tile != null && tile.block() != Blocks.air && tile.target().getTeam() == player.getTeam()){
|
if(tile != null && tile.block() != Blocks.air && tile.getTeam() == player.getTeam()){
|
||||||
Tile target = tile.target();
|
tile.block().drawSelect(tile);
|
||||||
target.block().drawSelect(target);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,8 +112,7 @@ public class OverlayRenderer{
|
|||||||
Lines.circle(v.x, v.y, 6 + Mathf.absin(Time.time(), 5f, 1f));
|
Lines.circle(v.x, v.y, 6 + Mathf.absin(Time.time(), 5f, 1f));
|
||||||
Draw.reset();
|
Draw.reset();
|
||||||
|
|
||||||
Tile tile = world.tileWorld(v.x, v.y);
|
Tile tile = world.ltileWorld(v.x, v.y);
|
||||||
if(tile != null) tile = tile.target();
|
|
||||||
if(tile != null && tile.interactable(player.getTeam()) && tile.block().acceptStack(player.item().item, player.item().amount, tile, player) > 0){
|
if(tile != null && tile.interactable(player.getTeam()) && tile.block().acceptStack(player.item().item, player.item().amount, tile, player) > 0){
|
||||||
Draw.color(Pal.place);
|
Draw.color(Pal.place);
|
||||||
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 1 + Mathf.absin(Time.time(), 5f, 1f));
|
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 1 + Mathf.absin(Time.time(), 5f, 1f));
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import io.anuke.arc.graphics.g2d.*;
|
|||||||
import io.anuke.arc.math.Mathf;
|
import io.anuke.arc.math.Mathf;
|
||||||
import io.anuke.arc.util.Tmp;
|
import io.anuke.arc.util.Tmp;
|
||||||
|
|
||||||
//TODO remove
|
|
||||||
public class Shapes{
|
public class Shapes{
|
||||||
|
|
||||||
public static void laser(String line, String edge, float x, float y, float x2, float y2, float scale){
|
public static void laser(String line, String edge, float x, float y, float x2, float y2, float scale){
|
||||||
|
|||||||
@@ -96,9 +96,8 @@ public class DesktopInput extends InputHandler{
|
|||||||
|
|
||||||
for(int x = dresult.x; x <= dresult.x2; x++){
|
for(int x = dresult.x; x <= dresult.x2; x++){
|
||||||
for(int y = dresult.y; y <= dresult.y2; y++){
|
for(int y = dresult.y; y <= dresult.y2; y++){
|
||||||
Tile tile = world.tile(x, y);
|
Tile tile = world.ltile(x, y);
|
||||||
if(tile == null || !validBreak(tile.x, tile.y)) continue;
|
if(tile == null || !validBreak(tile.x, tile.y)) continue;
|
||||||
tile = tile.target();
|
|
||||||
|
|
||||||
Draw.color(Pal.removeBack);
|
Draw.color(Pal.removeBack);
|
||||||
Lines.square(tile.drawx(), tile.drawy() - 1, tile.block().size * tilesize / 2f - 1);
|
Lines.square(tile.drawx(), tile.drawy() - 1, tile.block().size * tilesize / 2f - 1);
|
||||||
@@ -175,7 +174,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY());
|
Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY());
|
||||||
|
|
||||||
if(cursor != null){
|
if(cursor != null){
|
||||||
cursor = cursor.target();
|
cursor = cursor.link();
|
||||||
|
|
||||||
cursorType = cursor.block().getCursor(cursor);
|
cursorType = cursor.block().getCursor(cursor);
|
||||||
|
|
||||||
@@ -257,7 +256,7 @@ public class DesktopInput extends InputHandler{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(selected != null){
|
if(selected != null){
|
||||||
tryDropItems(selected.target(), Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
tryDropItems(selected.link(), Core.input.mouseWorld().x, Core.input.mouseWorld().y);
|
||||||
}
|
}
|
||||||
|
|
||||||
mode = none;
|
mode = none;
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ public abstract class InputHandler implements InputProcessor{
|
|||||||
|
|
||||||
/** Handles tile tap events that are not platform specific. */
|
/** Handles tile tap events that are not platform specific. */
|
||||||
boolean tileTapped(Tile tile){
|
boolean tileTapped(Tile tile){
|
||||||
tile = tile.target();
|
tile = tile.link();
|
||||||
|
|
||||||
boolean consumed = false, showedInventory = false;
|
boolean consumed = false, showedInventory = false;
|
||||||
|
|
||||||
@@ -195,16 +195,17 @@ public abstract class InputHandler implements InputProcessor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!showedInventory){
|
//clear when the player taps on something else
|
||||||
frag.inv.hide();
|
if(!consumed && !mobile && player.isBuilding() && block == null){
|
||||||
}
|
|
||||||
|
|
||||||
if(!consumed && player.isBuilding()){
|
|
||||||
player.clearBuilding();
|
player.clearBuilding();
|
||||||
block = null;
|
block = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!showedInventory){
|
||||||
|
frag.inv.hide();
|
||||||
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -331,7 +332,7 @@ public abstract class InputHandler implements InputProcessor{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void breakBlock(int x, int y){
|
public void breakBlock(int x, int y){
|
||||||
Tile tile = world.tile(x, y).target();
|
Tile tile = world.ltile(x, y);
|
||||||
player.addBuildRequest(new BuildRequest(tile.x, tile.y));
|
player.addBuildRequest(new BuildRequest(tile.x, tile.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,8 +87,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
player.setMineTile(null);
|
player.setMineTile(null);
|
||||||
player.target = unit;
|
player.target = unit;
|
||||||
}else{
|
}else{
|
||||||
Tile tile = world.tileWorld(x, y);
|
Tile tile = world.ltileWorld(x, y);
|
||||||
if(tile != null) tile = tile.target();
|
|
||||||
|
|
||||||
if(tile != null && tile.synthetic() && state.teams.areEnemies(player.getTeam(), tile.getTeam())){
|
if(tile != null && tile.synthetic() && state.teams.areEnemies(player.getTeam(), tile.getTeam())){
|
||||||
TileEntity entity = tile.entity;
|
TileEntity entity = tile.entity;
|
||||||
@@ -276,12 +275,11 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
}
|
}
|
||||||
}).update(l -> l.setChecked(mode == breaking));
|
}).update(l -> l.setChecked(mode == breaking));
|
||||||
|
|
||||||
//cancel button
|
//diagonal swap button
|
||||||
table.addImageButton("icon-cancel", "clear-partial", 16 * 2f, () -> {
|
table.addImageButton("icon-diagonal", "clear-toggle-partial", 16 * 2f, () -> {
|
||||||
player.clearBuilding();
|
Core.settings.put("swapdiagonal", !Core.settings.getBool("swapdiagonal"));
|
||||||
mode = none;
|
Core.settings.save();
|
||||||
block = null;
|
}).update(l -> l.setChecked(Core.settings.getBool("swapdiagonal")));
|
||||||
}).visible(() -> player.isBuilding() || block != null || mode == breaking);
|
|
||||||
|
|
||||||
//rotate button
|
//rotate button
|
||||||
table.addImageButton("icon-arrow", "clear-partial", 16 * 2f, () -> rotation = Mathf.mod(rotation + 1, 4))
|
table.addImageButton("icon-arrow", "clear-partial", 16 * 2f, () -> rotation = Mathf.mod(rotation + 1, 4))
|
||||||
@@ -311,6 +309,15 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
selection.clear();
|
selection.clear();
|
||||||
selecting = false;
|
selecting = false;
|
||||||
}).visible(() -> !selection.isEmpty());
|
}).visible(() -> !selection.isEmpty());
|
||||||
|
|
||||||
|
Core.scene.table(t -> {
|
||||||
|
t.bottom().left().visible(() -> player.isBuilding() || block != null || mode == breaking);
|
||||||
|
t.addImageTextButton("$cancel", "icon-cancel", 16*2, () -> {
|
||||||
|
player.clearBuilding();
|
||||||
|
mode = none;
|
||||||
|
block = null;
|
||||||
|
}).width(155f);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -408,9 +415,8 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
|
|
||||||
for(int x = dresult.x; x <= dresult.x2; x++){
|
for(int x = dresult.x; x <= dresult.x2; x++){
|
||||||
for(int y = dresult.y; y <= dresult.y2; y++){
|
for(int y = dresult.y; y <= dresult.y2; y++){
|
||||||
Tile other = world.tile(x, y);
|
Tile other = world.ltile(x, y);
|
||||||
if(other == null || !validBreak(other.x, other.y)) continue;
|
if(other == null || !validBreak(other.x, other.y)) continue;
|
||||||
other = other.target();
|
|
||||||
|
|
||||||
Draw.color(Pal.removeBack);
|
Draw.color(Pal.removeBack);
|
||||||
Lines.square(other.drawx(), other.drawy() - 1, other.block().size * tilesize / 2f - 1);
|
Lines.square(other.drawx(), other.drawy() - 1, other.block().size * tilesize / 2f - 1);
|
||||||
@@ -506,12 +512,10 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
int wx = lineStartX + x * Mathf.sign(tileX - lineStartX);
|
int wx = lineStartX + x * Mathf.sign(tileX - lineStartX);
|
||||||
int wy = lineStartY + y * Mathf.sign(tileY - lineStartY);
|
int wy = lineStartY + y * Mathf.sign(tileY - lineStartY);
|
||||||
|
|
||||||
Tile tar = world.tile(wx, wy);
|
Tile tar = world.ltile(wx, wy);
|
||||||
|
|
||||||
if(tar == null) continue;
|
if(tar == null) continue;
|
||||||
|
|
||||||
tar = tar.target();
|
|
||||||
|
|
||||||
if(!hasRequest(world.tile(tar.x, tar.y)) && validBreak(tar.x, tar.y)){
|
if(!hasRequest(world.tile(tar.x, tar.y)) && validBreak(tar.x, tar.y)){
|
||||||
PlaceRequest request = new PlaceRequest(tar.x, tar.y);
|
PlaceRequest request = new PlaceRequest(tar.x, tar.y);
|
||||||
request.scale = 1f;
|
request.scale = 1f;
|
||||||
@@ -527,7 +531,7 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
|
|
||||||
if(tile == null) return false;
|
if(tile == null) return false;
|
||||||
|
|
||||||
tryDropItems(tile.target(), Core.input.mouseWorld(screenX, screenY).x, Core.input.mouseWorld(screenX, screenY).y);
|
tryDropItems(tile.link(), Core.input.mouseWorld(screenX, screenY).x, Core.input.mouseWorld(screenX, screenY).y);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -577,11 +581,11 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){
|
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){
|
||||||
//add to selection queue if it's a valid place position
|
//add to selection queue if it's a valid place position
|
||||||
selection.add(lastPlaced = new PlaceRequest(cursor.x, cursor.y, block, rotation));
|
selection.add(lastPlaced = new PlaceRequest(cursor.x, cursor.y, block, rotation));
|
||||||
}else if(mode == breaking && validBreak(cursor.target().x, cursor.target().y) && !hasRequest(cursor.target())){
|
}else if(mode == breaking && validBreak(cursor.link().x, cursor.link().y) && !hasRequest(cursor.link())){
|
||||||
//add to selection queue if it's a valid BREAK position
|
//add to selection queue if it's a valid BREAK position
|
||||||
cursor = cursor.target();
|
cursor = cursor.link();
|
||||||
selection.add(new PlaceRequest(cursor.x, cursor.y));
|
selection.add(new PlaceRequest(cursor.x, cursor.y));
|
||||||
}else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.target())){
|
}else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.link())){
|
||||||
tryBeginMine(cursor);
|
tryBeginMine(cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
40
core/src/io/anuke/mindustry/io/JsonIO.java
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
package io.anuke.mindustry.io;
|
||||||
|
|
||||||
|
import io.anuke.arc.util.serialization.Json;
|
||||||
|
import io.anuke.arc.util.serialization.JsonValue;
|
||||||
|
import io.anuke.mindustry.Vars;
|
||||||
|
import io.anuke.mindustry.game.Rules;
|
||||||
|
import io.anuke.mindustry.game.SpawnGroup;
|
||||||
|
import io.anuke.mindustry.type.ContentType;
|
||||||
|
import io.anuke.mindustry.type.Zone;
|
||||||
|
|
||||||
|
public class JsonIO{
|
||||||
|
private static Json json = new Json(){{
|
||||||
|
setIgnoreUnknownFields(true);
|
||||||
|
setElementType(Rules.class, "spawns", SpawnGroup.class);
|
||||||
|
|
||||||
|
setSerializer(Zone.class, new Serializer<Zone>(){
|
||||||
|
@Override
|
||||||
|
public void write(Json json, Zone object, Class knownType){
|
||||||
|
json.writeValue(object.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Zone read(Json json, JsonValue jsonData, Class type){
|
||||||
|
return Vars.content.getByName(ContentType.zone, jsonData.asString());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}};
|
||||||
|
|
||||||
|
public static String write(Object object){
|
||||||
|
return json.toJson(object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> T read(Class<T> type, String string){
|
||||||
|
return json.fromJson(type, string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String print(String in){
|
||||||
|
return json.prettyPrint(in);
|
||||||
|
}
|
||||||
|
}
|
||||||
227
core/src/io/anuke/mindustry/io/LegacyMapIO.java
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
package io.anuke.mindustry.io;
|
||||||
|
|
||||||
|
import io.anuke.arc.collection.*;
|
||||||
|
import io.anuke.arc.files.FileHandle;
|
||||||
|
import io.anuke.arc.graphics.Color;
|
||||||
|
import io.anuke.arc.graphics.Pixmap;
|
||||||
|
import io.anuke.arc.util.Pack;
|
||||||
|
import io.anuke.arc.util.Structs;
|
||||||
|
import io.anuke.arc.util.serialization.Json;
|
||||||
|
import io.anuke.mindustry.content.Blocks;
|
||||||
|
import io.anuke.mindustry.game.SpawnGroup;
|
||||||
|
import io.anuke.mindustry.game.Team;
|
||||||
|
import io.anuke.mindustry.io.MapIO.TileProvider;
|
||||||
|
import io.anuke.mindustry.maps.Map;
|
||||||
|
import io.anuke.mindustry.type.ContentType;
|
||||||
|
import io.anuke.mindustry.world.*;
|
||||||
|
import io.anuke.mindustry.world.LegacyColorMapper.LegacyBlock;
|
||||||
|
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||||
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.zip.InflaterInputStream;
|
||||||
|
|
||||||
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
|
/** Map IO for the "old" .mmap format.
|
||||||
|
* Differentiate between legacy maps and new maps by checking the extension (or the header).*/
|
||||||
|
public class LegacyMapIO{
|
||||||
|
private static final ObjectMap<String, String> fallback = ObjectMap.of("alpha-dart-mech-pad", "dart-mech-pad");
|
||||||
|
private static final Json json = new Json();
|
||||||
|
|
||||||
|
/* Convert a map from the old format to the new format. */
|
||||||
|
public static void convertMap(FileHandle in, FileHandle out) throws IOException{
|
||||||
|
Map map = readMap(in, true);
|
||||||
|
|
||||||
|
String waves = map.tags.get("waves", "[]");
|
||||||
|
Array<SpawnGroup> groups = new Array<>(json.fromJson(SpawnGroup[].class, waves));
|
||||||
|
|
||||||
|
Tile[][] tiles = world.createTiles(map.width, map.height);
|
||||||
|
for(int x = 0; x < map.width; x++){
|
||||||
|
for(int y = 0; y < map.height; y++){
|
||||||
|
tiles[x][y] = new CachedTile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
state.rules.spawns = groups;
|
||||||
|
readTiles(map, tiles);
|
||||||
|
MapIO.writeMap(out, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map readMap(FileHandle file, boolean custom) throws IOException{
|
||||||
|
try(DataInputStream stream = new DataInputStream(file.read(1024))){
|
||||||
|
StringMap tags = new StringMap();
|
||||||
|
|
||||||
|
//meta is uncompressed
|
||||||
|
int version = stream.readInt();
|
||||||
|
int build = stream.readInt();
|
||||||
|
short width = stream.readShort(), height = stream.readShort();
|
||||||
|
byte tagAmount = stream.readByte();
|
||||||
|
|
||||||
|
for(int i = 0; i < tagAmount; i++){
|
||||||
|
String name = stream.readUTF();
|
||||||
|
String value = stream.readUTF();
|
||||||
|
tags.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Map(file, width, height, tags, custom, version, build);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readTiles(Map map, Tile[][] tiles) throws IOException{
|
||||||
|
readTiles(map, (x, y) -> tiles[x][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void readTiles(Map map, TileProvider tiles) throws IOException{
|
||||||
|
readTiles(map.file, map.width, map.height, tiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{
|
||||||
|
readTiles(file, width, height, (x, y) -> tiles[x][y]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void readTiles(FileHandle file, int width, int height, TileProvider tiles) throws IOException{
|
||||||
|
try(BufferedInputStream input = file.read(bufferSize)){
|
||||||
|
|
||||||
|
//read map
|
||||||
|
{
|
||||||
|
DataInputStream stream = new DataInputStream(input);
|
||||||
|
|
||||||
|
stream.readInt(); //version
|
||||||
|
stream.readInt(); //build
|
||||||
|
stream.readInt(); //width + height
|
||||||
|
byte tagAmount = stream.readByte();
|
||||||
|
|
||||||
|
for(int i = 0; i < tagAmount; i++){
|
||||||
|
stream.readUTF(); //key
|
||||||
|
stream.readUTF(); //val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try(DataInputStream stream = new DataInputStream(new InflaterInputStream(input))){
|
||||||
|
|
||||||
|
try{
|
||||||
|
byte mapped = stream.readByte();
|
||||||
|
IntMap<Block> idmap = new IntMap<>();
|
||||||
|
IntMap<String> namemap = new IntMap<>();
|
||||||
|
|
||||||
|
for(int i = 0; i < mapped; i++){
|
||||||
|
byte type = stream.readByte();
|
||||||
|
short total = stream.readShort();
|
||||||
|
|
||||||
|
for(int j = 0; j < total; j++){
|
||||||
|
String name = stream.readUTF();
|
||||||
|
if(type == 1){
|
||||||
|
Block res = content.getByName(ContentType.block, fallback.get(name, name));
|
||||||
|
idmap.put(j, res == null ? Blocks.air : res);
|
||||||
|
namemap.put(j, fallback.get(name, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//read floor and create tiles first
|
||||||
|
for(int i = 0; i < width * height; i++){
|
||||||
|
int x = i % width, y = i / width;
|
||||||
|
int floorid = stream.readUnsignedByte();
|
||||||
|
int oreid = stream.readUnsignedByte();
|
||||||
|
int consecutives = stream.readUnsignedByte();
|
||||||
|
|
||||||
|
Tile tile = tiles.get(x, y);
|
||||||
|
tile.setFloor((Floor)idmap.get(floorid));
|
||||||
|
tile.setOverlay(idmap.get(oreid));
|
||||||
|
|
||||||
|
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||||
|
int newx = j % width, newy = j / width;
|
||||||
|
Tile newTile = tiles.get(newx, newy);
|
||||||
|
newTile.setFloor((Floor)idmap.get(floorid));
|
||||||
|
newTile.setOverlay(idmap.get(oreid));
|
||||||
|
}
|
||||||
|
|
||||||
|
i += consecutives;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read blocks
|
||||||
|
for(int i = 0; i < width * height; i++){
|
||||||
|
int x = i % width, y = i / width;
|
||||||
|
int id = stream.readUnsignedByte();
|
||||||
|
Block block = idmap.get(id);
|
||||||
|
if(block == null) block = Blocks.air;
|
||||||
|
|
||||||
|
Tile tile = tiles.get(x, y);
|
||||||
|
//the spawn block is saved in the block tile layer in older maps, shift it to the overlay
|
||||||
|
if(block != Blocks.spawn){
|
||||||
|
tile.setBlock(block);
|
||||||
|
}else{
|
||||||
|
tile.setOverlay(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(namemap.get(id, "").equals("part")){
|
||||||
|
stream.readByte(); //link
|
||||||
|
}else if(tile.entity != null){
|
||||||
|
byte tr = stream.readByte();
|
||||||
|
stream.readShort(); //read health (which is actually irrelevant)
|
||||||
|
|
||||||
|
byte team = Pack.leftByte(tr);
|
||||||
|
byte rotation = Pack.rightByte(tr);
|
||||||
|
|
||||||
|
tile.setTeam(Team.all[team]);
|
||||||
|
tile.entity.health = tile.block().health;
|
||||||
|
tile.rotation(rotation);
|
||||||
|
|
||||||
|
if(tile.block() == Blocks.liquidSource || tile.block() == Blocks.unloader || tile.block() == Blocks.sorter){
|
||||||
|
stream.readByte(); //these blocks have an extra config byte, read it
|
||||||
|
}
|
||||||
|
}else{ //no entity/part, read consecutives
|
||||||
|
int consecutives = stream.readUnsignedByte();
|
||||||
|
|
||||||
|
for(int j = i + 1; j < i + 1 + consecutives; j++){
|
||||||
|
int newx = j % width, newy = j / width;
|
||||||
|
tiles.get(newx, newy).setBlock(block);
|
||||||
|
}
|
||||||
|
|
||||||
|
i += consecutives;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}finally{
|
||||||
|
content.setTemporaryMapper(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Reads a pixmap in the 3.5 pixmap format. */
|
||||||
|
public static void readPixmap(Pixmap pixmap, Tile[][] tiles){
|
||||||
|
for(int x = 0; x < pixmap.getWidth(); x++){
|
||||||
|
for(int y = 0; y < pixmap.getHeight(); y++){
|
||||||
|
int color = pixmap.getPixel(x, pixmap.getHeight() - 1 - y);
|
||||||
|
LegacyBlock block = LegacyColorMapper.get(color);
|
||||||
|
Tile tile = tiles[x][y];
|
||||||
|
|
||||||
|
tile.setFloor(block.floor);
|
||||||
|
tile.setBlock(block.wall);
|
||||||
|
if(block.ore != null) tile.setOverlay(block.ore);
|
||||||
|
|
||||||
|
//place core
|
||||||
|
if(color == Color.rgba8888(Color.GREEN)){
|
||||||
|
for(int dx = 0; dx < 3; dx++){
|
||||||
|
for(int dy = 0; dy < 3; dy++){
|
||||||
|
int worldx = dx - 1 + x;
|
||||||
|
int worldy = dy - 1 + y;
|
||||||
|
|
||||||
|
//multiblock parts
|
||||||
|
if(Structs.inBounds(worldx, worldy, pixmap.getWidth(), pixmap.getHeight())){
|
||||||
|
Tile write = tiles[worldx][worldy];
|
||||||
|
write.setBlock(BlockPart.get(dx - 1, dy - 1));
|
||||||
|
write.setTeam(Team.blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//actual core parts
|
||||||
|
tile.setBlock(Blocks.coreShard);
|
||||||
|
tile.setTeam(Team.blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||