Formatting
This commit is contained in:
@@ -59,7 +59,8 @@ public class AndroidTextFieldDialog{
|
|||||||
while(!isBuild){
|
while(!isBuild){
|
||||||
try{
|
try{
|
||||||
Thread.sleep(10);
|
Thread.sleep(10);
|
||||||
} catch (InterruptedException e) { }
|
}catch(InterruptedException e){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -8,12 +8,9 @@ import android.support.v4.app.FragmentManager;
|
|||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
|
|
||||||
import org.sufficientlysecure.donations.DonationsFragment;
|
import org.sufficientlysecure.donations.DonationsFragment;
|
||||||
|
|
||||||
public class DonationsActivity extends FragmentActivity{
|
public class DonationsActivity extends FragmentActivity{
|
||||||
DonationsFragment donationsFragment;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Google
|
* Google
|
||||||
*/
|
*/
|
||||||
@@ -22,6 +19,7 @@ public class DonationsActivity extends FragmentActivity {
|
|||||||
"mindustry.donation.1", "mindustry.donation.2", "mindustry.donation.5",
|
"mindustry.donation.1", "mindustry.donation.2", "mindustry.donation.5",
|
||||||
"mindustry.donation.10", "mindustry.donation.15",
|
"mindustry.donation.10", "mindustry.donation.15",
|
||||||
"mindustry.donation.25", "mindustry.donation.50"};
|
"mindustry.donation.25", "mindustry.donation.50"};
|
||||||
|
DonationsFragment donationsFragment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the activity is first created.
|
* Called when the activity is first created.
|
||||||
@@ -50,7 +48,8 @@ public class DonationsActivity extends FragmentActivity {
|
|||||||
super.onStart();
|
super.onStart();
|
||||||
Button b = ((Button) findViewById(org.sufficientlysecure.donations.R.id.donations__google_android_market_donate_button));
|
Button b = ((Button) findViewById(org.sufficientlysecure.donations.R.id.donations__google_android_market_donate_button));
|
||||||
b.setOnClickListener(new View.OnClickListener(){
|
b.setOnClickListener(new View.OnClickListener(){
|
||||||
@Override public void onClick(View view) {
|
@Override
|
||||||
|
public void onClick(View view){
|
||||||
donationsFragment.donateGoogleOnClick(donationsFragment.getView());
|
donationsFragment.donateGoogleOnClick(donationsFragment.getView());
|
||||||
b.setEnabled(false);
|
b.setEnabled(false);
|
||||||
}
|
}
|
||||||
@@ -58,7 +57,6 @@ public class DonationsActivity extends FragmentActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Needed for Google Play In-app Billing. It uses startIntentSenderForResult(). The result is not propagated to
|
* Needed for Google Play In-app Billing. It uses startIntentSenderForResult(). The result is not propagated to
|
||||||
* the Fragment like in startActivityForResult(). Thus we need to propagate manually to our Fragment.
|
* the Fragment like in startActivityForResult(). Thus we need to propagate manually to our Fragment.
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ public class TextFieldDialogListener extends ClickListener{
|
|||||||
private int type;
|
private int type;
|
||||||
private int max;
|
private int max;
|
||||||
|
|
||||||
|
//type - 0 is text, 1 is numbers, 2 is decimals
|
||||||
|
public TextFieldDialogListener(TextField field, int type, int max){
|
||||||
|
this.field = field;
|
||||||
|
this.type = type;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
public static void add(TextField field, int type, int max){
|
public static void add(TextField field, int type, int max){
|
||||||
field.addListener(new TextFieldDialogListener(field, type, max));
|
field.addListener(new TextFieldDialogListener(field, type, max));
|
||||||
field.addListener(new InputListener(){
|
field.addListener(new InputListener(){
|
||||||
@@ -29,13 +36,6 @@ public class TextFieldDialogListener extends ClickListener{
|
|||||||
add(field, 0, 16);
|
add(field, 0, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
//type - 0 is text, 1 is numbers, 2 is decimals
|
|
||||||
public TextFieldDialogListener(TextField field, int type, int max){
|
|
||||||
this.field = field;
|
|
||||||
this.type = type;
|
|
||||||
this.max = max;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clicked(final InputEvent event, float x, float y){
|
public void clicked(final InputEvent event, float x, float y){
|
||||||
|
|
||||||
if(Gdx.app.getType() == ApplicationType.Desktop) return;
|
if(Gdx.app.getType() == ApplicationType.Desktop) return;
|
||||||
|
|||||||
@@ -11,45 +11,6 @@ import java.lang.annotation.Target;
|
|||||||
*/
|
*/
|
||||||
public class Annotations{
|
public class Annotations{
|
||||||
|
|
||||||
/**Marks a method as invokable remotely across a server/client connection.*/
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.CLASS)
|
|
||||||
public @interface Remote {
|
|
||||||
/**Specifies the locations from which this method can be invoked.*/
|
|
||||||
Loc targets() default Loc.server;
|
|
||||||
/**Specifies which methods are generated. Only affects server-to-client methods.*/
|
|
||||||
Variant variants() default Variant.all;
|
|
||||||
/**The local locations where this method is called locally, when invoked.*/
|
|
||||||
Loc called() default Loc.none;
|
|
||||||
/**Whether to forward this packet to all other clients upon recieval. Client only.*/
|
|
||||||
boolean forward() default false;
|
|
||||||
/**Whether the packet for this method is sent with UDP instead of TCP.
|
|
||||||
* UDP is faster, but is prone to packet loss and duplication.*/
|
|
||||||
boolean unreliable() default false;
|
|
||||||
/**The simple class name where this method is placed.*/
|
|
||||||
String in() default "Call";
|
|
||||||
/**Priority of this event.*/
|
|
||||||
PacketPriority priority() default PacketPriority.normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Specifies that this method will be used to write classes of the type returned by {@link #value()}.<br>
|
|
||||||
* This method must return void and have two parameters, the first being of type {@link java.nio.ByteBuffer} and the second
|
|
||||||
* being the type returned by {@link #value()}.*/
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.CLASS)
|
|
||||||
public @interface WriteClass {
|
|
||||||
Class<?> value();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Specifies that this method will be used to read classes of the type returned by {@link #value()}. <br>
|
|
||||||
* This method must return the type returned by {@link #value()},
|
|
||||||
* and have one parameter, being of type {@link java.nio.ByteBuffer}.*/
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.CLASS)
|
|
||||||
public @interface ReadClass {
|
|
||||||
Class<?> value();
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum PacketPriority{
|
public enum PacketPriority{
|
||||||
/** Gets put in a queue and processed if not connected. */
|
/** Gets put in a queue and processed if not connected. */
|
||||||
normal,
|
normal,
|
||||||
@@ -96,4 +57,55 @@ public class Annotations {
|
|||||||
this.isAll = isAll;
|
this.isAll = isAll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Marks a method as invokable remotely across a server/client connection. */
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
public @interface Remote{
|
||||||
|
/** Specifies the locations from which this method can be invoked. */
|
||||||
|
Loc targets() default Loc.server;
|
||||||
|
|
||||||
|
/** Specifies which methods are generated. Only affects server-to-client methods. */
|
||||||
|
Variant variants() default Variant.all;
|
||||||
|
|
||||||
|
/** The local locations where this method is called locally, when invoked. */
|
||||||
|
Loc called() default Loc.none;
|
||||||
|
|
||||||
|
/** Whether to forward this packet to all other clients upon recieval. Client only. */
|
||||||
|
boolean forward() default false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the packet for this method is sent with UDP instead of TCP.
|
||||||
|
* UDP is faster, but is prone to packet loss and duplication.
|
||||||
|
*/
|
||||||
|
boolean unreliable() default false;
|
||||||
|
|
||||||
|
/** The simple class name where this method is placed. */
|
||||||
|
String in() default "Call";
|
||||||
|
|
||||||
|
/** Priority of this event. */
|
||||||
|
PacketPriority priority() default PacketPriority.normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that this method will be used to write classes of the type returned by {@link #value()}.<br>
|
||||||
|
* This method must return void and have two parameters, the first being of type {@link java.nio.ByteBuffer} and the second
|
||||||
|
* being the type returned by {@link #value()}.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
public @interface WriteClass{
|
||||||
|
Class<?> value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies that this method will be used to read classes of the type returned by {@link #value()}. <br>
|
||||||
|
* This method must return the type returned by {@link #value()},
|
||||||
|
* and have one parameter, being of type {@link java.nio.ByteBuffer}.
|
||||||
|
*/
|
||||||
|
@Target(ElementType.METHOD)
|
||||||
|
@Retention(RetentionPolicy.CLASS)
|
||||||
|
public @interface ReadClass{
|
||||||
|
Class<?> value();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,16 @@ import javax.tools.Diagnostic.Kind;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**This class finds reader and writer methods annotated by the {@link io.anuke.annotations.Annotations.WriteClass}
|
/**
|
||||||
* and {@link io.anuke.annotations.Annotations.ReadClass} annotations.*/
|
* This class finds reader and writer methods annotated by the {@link io.anuke.annotations.Annotations.WriteClass}
|
||||||
|
* and {@link io.anuke.annotations.Annotations.ReadClass} annotations.
|
||||||
|
*/
|
||||||
public class IOFinder{
|
public class IOFinder{
|
||||||
|
|
||||||
/**Finds all class serializers for all types and returns them. Logs errors when necessary.
|
/**
|
||||||
* Maps fully qualified class names to their serializers.*/
|
* Finds all class serializers for all types and returns them. Logs errors when necessary.
|
||||||
|
* Maps fully qualified class names to their serializers.
|
||||||
|
*/
|
||||||
public HashMap<String, ClassSerializer> findSerializers(RoundEnvironment env){
|
public HashMap<String, ClassSerializer> findSerializers(RoundEnvironment env){
|
||||||
HashMap<String, ClassSerializer> result = new HashMap<>();
|
HashMap<String, ClassSerializer> result = new HashMap<>();
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ public class MethodEntry {
|
|||||||
public final String targetMethod;
|
public final String targetMethod;
|
||||||
/** Whether this method can be called on a client/server. */
|
/** Whether this method can be called on a client/server. */
|
||||||
public final Loc where;
|
public final Loc where;
|
||||||
/**Whether an additional 'one' and 'all' method variant is generated. At least one of these must be true.
|
/**
|
||||||
* Only applicable to client (server-invoked) methods.*/
|
* Whether an additional 'one' and 'all' method variant is generated. At least one of these must be true.
|
||||||
|
* Only applicable to client (server-invoked) methods.
|
||||||
|
*/
|
||||||
public final Variant target;
|
public final Variant target;
|
||||||
/** Whether this method is called locally as well as remotely. */
|
/** Whether this method is called locally as well as remotely. */
|
||||||
public final Loc local;
|
public final Loc local;
|
||||||
|
|||||||
@@ -23,11 +23,14 @@ public class RemoteReadGenerator {
|
|||||||
this.serializers = serializers;
|
this.serializers = serializers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Generates a class for reading remote invoke packets.
|
/**
|
||||||
|
* Generates a class for reading remote invoke packets.
|
||||||
|
*
|
||||||
* @param entries List of methods to use/
|
* @param entries List of methods to use/
|
||||||
* @param className Simple target class name.
|
* @param className Simple target class name.
|
||||||
* @param packageName Full target package name.
|
* @param packageName Full target package name.
|
||||||
* @param needsPlayer Whether this read method requires a reference to the player sender.*/
|
* @param needsPlayer Whether this read method requires a reference to the player sender.
|
||||||
|
*/
|
||||||
public void generateFor(List<MethodEntry> entries, String className, String packageName, boolean needsPlayer)
|
public void generateFor(List<MethodEntry> entries, String className, String packageName, boolean needsPlayer)
|
||||||
throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{
|
throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{
|
||||||
|
|
||||||
|
|||||||
@@ -19,14 +19,54 @@ import io.anuke.mindustry.io.Version;
|
|||||||
import io.anuke.mindustry.net.Net;
|
import io.anuke.mindustry.net.Net;
|
||||||
import io.anuke.ucore.entities.Entities;
|
import io.anuke.ucore.entities.Entities;
|
||||||
import io.anuke.ucore.entities.EntityGroup;
|
import io.anuke.ucore.entities.EntityGroup;
|
||||||
import io.anuke.ucore.entities.trait.DrawTrait;
|
|
||||||
import io.anuke.ucore.entities.impl.EffectEntity;
|
import io.anuke.ucore.entities.impl.EffectEntity;
|
||||||
|
import io.anuke.ucore.entities.trait.DrawTrait;
|
||||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||||
import io.anuke.ucore.util.OS;
|
import io.anuke.ucore.util.OS;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class Vars{
|
public class Vars{
|
||||||
|
//respawn time in frames
|
||||||
|
public static final float respawnduration = 60 * 4;
|
||||||
|
//time between waves in frames (on normal mode)
|
||||||
|
public static final float wavespace = 60 * 60 * 2f;
|
||||||
|
//waves can last no longer than 3 minutes, otherwise the next one spawns
|
||||||
|
public static final float maxwavespace = 60 * 60 * 4f;
|
||||||
|
//set ridiculously high for now
|
||||||
|
public static final float coreBuildRange = 800999f;
|
||||||
|
//discord group URL
|
||||||
|
public static final String discordURL = "https://discord.gg/BKADYds";
|
||||||
|
public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases";
|
||||||
|
public static final int maxTextLength = 150;
|
||||||
|
public static final int maxNameLength = 40;
|
||||||
|
public static final int maxCharNameLength = 20;
|
||||||
|
public static final int saveSlots = 64;
|
||||||
|
public static final float itemSize = 5f;
|
||||||
|
public static final int tilesize = 8;
|
||||||
|
public static final Locale[] locales = {new Locale("en"), new Locale("fr"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl"),
|
||||||
|
new Locale("de"), new Locale("pt", "BR"), new Locale("ko"), new Locale("in", "ID"), new Locale("ita"), new Locale("es")};
|
||||||
|
public static final Color[] playerColors = {
|
||||||
|
Color.valueOf("82759a"),
|
||||||
|
Color.valueOf("c0c1c5"),
|
||||||
|
Color.valueOf("fff0e7"),
|
||||||
|
Color.valueOf("7d2953"),
|
||||||
|
Color.valueOf("ff074e"),
|
||||||
|
Color.valueOf("ff072a"),
|
||||||
|
Color.valueOf("ff76a6"),
|
||||||
|
Color.valueOf("a95238"),
|
||||||
|
Color.valueOf("ffa108"),
|
||||||
|
Color.valueOf("feeb2c"),
|
||||||
|
Color.valueOf("ffcaa8"),
|
||||||
|
Color.valueOf("008551"),
|
||||||
|
Color.valueOf("00e339"),
|
||||||
|
Color.valueOf("423c7b"),
|
||||||
|
Color.valueOf("4b5ef1"),
|
||||||
|
Color.valueOf("2cabfe"),
|
||||||
|
};
|
||||||
|
//server port
|
||||||
|
public static final int port = 6567;
|
||||||
|
public static final int webPort = 6568;
|
||||||
public static boolean testMobile;
|
public static boolean testMobile;
|
||||||
//shorthand for whether or not this is running on android or ios
|
//shorthand for whether or not this is running on android or ios
|
||||||
public static boolean mobile;
|
public static boolean mobile;
|
||||||
@@ -34,21 +74,6 @@ public class Vars{
|
|||||||
public static boolean android;
|
public static boolean android;
|
||||||
//shorthand for whether or not this is running on GWT
|
//shorthand for whether or not this is running on GWT
|
||||||
public static boolean gwt;
|
public static boolean gwt;
|
||||||
|
|
||||||
//respawn time in frames
|
|
||||||
public static final float respawnduration = 60*4;
|
|
||||||
//time between waves in frames (on normal mode)
|
|
||||||
public static final float wavespace = 60*60*2f;
|
|
||||||
//waves can last no longer than 3 minutes, otherwise the next one spawns
|
|
||||||
public static final float maxwavespace = 60*60*4f;
|
|
||||||
|
|
||||||
//set ridiculously high for now
|
|
||||||
public static final float coreBuildRange = 800999f;
|
|
||||||
//discord group URL
|
|
||||||
public static final String discordURL = "https://discord.gg/BKADYds";
|
|
||||||
|
|
||||||
public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases";
|
|
||||||
|
|
||||||
//directory for user-created map data
|
//directory for user-created map data
|
||||||
public static FileHandle customMapDirectory;
|
public static FileHandle customMapDirectory;
|
||||||
//save file directory
|
//save file directory
|
||||||
@@ -74,54 +99,12 @@ public class Vars{
|
|||||||
public static boolean showUI = true;
|
public static boolean showUI = true;
|
||||||
//whether to show block debug
|
//whether to show block debug
|
||||||
public static boolean showBlockDebug = false;
|
public static boolean showBlockDebug = false;
|
||||||
|
|
||||||
public static boolean showFog = true;
|
public static boolean showFog = true;
|
||||||
|
|
||||||
public static final int maxTextLength = 150;
|
|
||||||
public static final int maxNameLength = 40;
|
|
||||||
public static final int maxCharNameLength = 20;
|
|
||||||
|
|
||||||
public static boolean headless = false;
|
public static boolean headless = false;
|
||||||
|
|
||||||
public static float controllerMin = 0.25f;
|
public static float controllerMin = 0.25f;
|
||||||
|
|
||||||
public static float baseControllerSpeed = 11f;
|
public static float baseControllerSpeed = 11f;
|
||||||
|
|
||||||
public static final int saveSlots = 64;
|
|
||||||
|
|
||||||
public static final float itemSize = 5f;
|
|
||||||
|
|
||||||
//only if smoothCamera
|
//only if smoothCamera
|
||||||
public static boolean snapCamera = true;
|
public static boolean snapCamera = true;
|
||||||
|
|
||||||
public static final int tilesize = 8;
|
|
||||||
|
|
||||||
public static final Locale[] locales = {new Locale("en"), new Locale("fr"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl"),
|
|
||||||
new Locale("de"), new Locale("pt", "BR"), new Locale("ko"), new Locale("in", "ID"), new Locale("ita"), new Locale("es")};
|
|
||||||
|
|
||||||
public static final Color[] playerColors = {
|
|
||||||
Color.valueOf("82759a"),
|
|
||||||
Color.valueOf("c0c1c5"),
|
|
||||||
Color.valueOf("fff0e7"),
|
|
||||||
Color.valueOf("7d2953"),
|
|
||||||
Color.valueOf("ff074e"),
|
|
||||||
Color.valueOf("ff072a"),
|
|
||||||
Color.valueOf("ff76a6"),
|
|
||||||
Color.valueOf("a95238"),
|
|
||||||
Color.valueOf("ffa108"),
|
|
||||||
Color.valueOf("feeb2c"),
|
|
||||||
Color.valueOf("ffcaa8"),
|
|
||||||
Color.valueOf("008551"),
|
|
||||||
Color.valueOf("00e339"),
|
|
||||||
Color.valueOf("423c7b"),
|
|
||||||
Color.valueOf("4b5ef1"),
|
|
||||||
Color.valueOf("2cabfe"),
|
|
||||||
};
|
|
||||||
|
|
||||||
//server port
|
|
||||||
public static final int port = 6567;
|
|
||||||
public static final int webPort = 6568;
|
|
||||||
|
|
||||||
public static GameState state;
|
public static GameState state;
|
||||||
public static ThreadHandler threads;
|
public static ThreadHandler threads;
|
||||||
|
|
||||||
|
|||||||
@@ -26,32 +26,53 @@ import static io.anuke.mindustry.Vars.*;
|
|||||||
|
|
||||||
//TODO consider using quadtrees for finding specific types of blocks within an area
|
//TODO consider using quadtrees for finding specific types of blocks within an area
|
||||||
//TODO maybe use Arrays instead of ObjectSets?
|
//TODO maybe use Arrays instead of ObjectSets?
|
||||||
/**Class used for indexing special target blocks for AI.*/
|
|
||||||
|
/**
|
||||||
|
* Class used for indexing special target blocks for AI.
|
||||||
|
*/
|
||||||
public class BlockIndexer{
|
public class BlockIndexer{
|
||||||
/**Size of one ore quadrant.*/
|
/**
|
||||||
|
* Size of one ore quadrant.
|
||||||
|
*/
|
||||||
private final static int oreQuadrantSize = 20;
|
private final static int oreQuadrantSize = 20;
|
||||||
/**Size of one structure quadrant.*/
|
/**
|
||||||
|
* Size of one structure quadrant.
|
||||||
|
*/
|
||||||
private final static int structQuadrantSize = 12;
|
private final static int structQuadrantSize = 12;
|
||||||
|
|
||||||
/**Set of all ores that are being scanned.*/
|
/**
|
||||||
|
* Set of all ores that are being scanned.
|
||||||
|
*/
|
||||||
private final ObjectSet<Item> scanOres = ObjectSet.with(Items.tungsten, Items.coal, Items.lead, Items.thorium, Items.titanium);
|
private final ObjectSet<Item> scanOres = ObjectSet.with(Items.tungsten, Items.coal, Items.lead, Items.thorium, Items.titanium);
|
||||||
/**Stores all ore quadtrants on the map.*/
|
|
||||||
private ObjectMap<Item, ObjectSet<Tile>> ores;
|
|
||||||
|
|
||||||
private final ObjectSet<Item> itemSet = new ObjectSet<>();
|
private final ObjectSet<Item> itemSet = new ObjectSet<>();
|
||||||
|
/**
|
||||||
/**Tags all quadrants.*/
|
* Stores all ore quadtrants on the map.
|
||||||
|
*/
|
||||||
|
private ObjectMap<Item, ObjectSet<Tile>> ores;
|
||||||
|
/**
|
||||||
|
* Tags all quadrants.
|
||||||
|
*/
|
||||||
private Bits[] structQuadrants;
|
private Bits[] structQuadrants;
|
||||||
|
|
||||||
/**Maps teams to a map of flagged tiles by type.*/
|
/**
|
||||||
|
* Maps teams to a map of flagged tiles by type.
|
||||||
|
*/
|
||||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> enemyMap = new ObjectMap<>();
|
private ObjectMap<BlockFlag, ObjectSet<Tile>> enemyMap = new ObjectMap<>();
|
||||||
/**Maps teams to a map of flagged tiles by type.*/
|
/**
|
||||||
|
* Maps teams to a map of flagged tiles by type.
|
||||||
|
*/
|
||||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> allyMap = new ObjectMap<>();
|
private ObjectMap<BlockFlag, ObjectSet<Tile>> allyMap = new ObjectMap<>();
|
||||||
/**Empty map for invalid teams.*/
|
/**
|
||||||
|
* Empty map for invalid teams.
|
||||||
|
*/
|
||||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> emptyMap = new ObjectMap<>();
|
private ObjectMap<BlockFlag, ObjectSet<Tile>> emptyMap = new ObjectMap<>();
|
||||||
/**Maps tile positions to their last known tile index data.*/
|
/**
|
||||||
|
* Maps tile positions to their last known tile index data.
|
||||||
|
*/
|
||||||
private IntMap<TileIndex> typeMap = new IntMap<>();
|
private IntMap<TileIndex> typeMap = new IntMap<>();
|
||||||
/**Empty array used for returning.*/
|
/**
|
||||||
|
* Empty array used for returning.
|
||||||
|
*/
|
||||||
private ObjectSet<Tile> emptyArray = new ObjectSet<>();
|
private ObjectSet<Tile> emptyArray = new ObjectSet<>();
|
||||||
|
|
||||||
public BlockIndexer(){
|
public BlockIndexer(){
|
||||||
@@ -94,12 +115,16 @@ public class BlockIndexer {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Get all allied blocks with a flag.*/
|
/**
|
||||||
|
* Get all allied blocks with a flag.
|
||||||
|
*/
|
||||||
public ObjectSet<Tile> getAllied(Team team, BlockFlag type){
|
public ObjectSet<Tile> getAllied(Team team, BlockFlag type){
|
||||||
return (state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray);
|
return (state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Get all enemy blocks with a flag.*/
|
/**
|
||||||
|
* Get all enemy blocks with a flag.
|
||||||
|
*/
|
||||||
public ObjectSet<Tile> getEnemy(Team team, BlockFlag type){
|
public ObjectSet<Tile> getEnemy(Team team, BlockFlag type){
|
||||||
return (!state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray);
|
return (!state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray);
|
||||||
}
|
}
|
||||||
@@ -134,15 +159,19 @@ public class BlockIndexer {
|
|||||||
return (TileEntity) closest;
|
return (TileEntity) closest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a set of tiles that have ores of the specified type nearby.
|
/**
|
||||||
|
* Returns a set of tiles that have ores of the specified type nearby.
|
||||||
* While each tile in the set is not guaranteed to have an ore directly on it,
|
* While each tile in the set is not guaranteed to have an ore directly on it,
|
||||||
* each tile will at least have an ore within {@link #oreQuadrantSize} / 2 blocks of it.
|
* each tile will at least have an ore within {@link #oreQuadrantSize} / 2 blocks of it.
|
||||||
* Only specific ore types are scanned. See {@link #scanOres}.*/
|
* Only specific ore types are scanned. See {@link #scanOres}.
|
||||||
|
*/
|
||||||
public ObjectSet<Tile> getOrePositions(Item item){
|
public ObjectSet<Tile> getOrePositions(Item item){
|
||||||
return ores.get(item, emptyArray);
|
return ores.get(item, emptyArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Find the closest ore block relative to a position.*/
|
/**
|
||||||
|
* Find the closest ore block relative to a position.
|
||||||
|
*/
|
||||||
public Tile findClosestOre(float xp, float yp, Item item){
|
public Tile findClosestOre(float xp, float yp, Item item){
|
||||||
Tile tile = Geometry.findClosest(xp, yp, world.indexer().getOrePositions(item));
|
Tile tile = Geometry.findClosest(xp, yp, world.indexer().getOrePositions(item));
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ import io.anuke.mindustry.type.Upgrade;
|
|||||||
public class Mechs implements ContentList{
|
public class Mechs implements ContentList{
|
||||||
public static Mech alpha, delta, tau, omega, dart, javelin, trident, halberd;
|
public static Mech alpha, delta, tau, omega, dart, javelin, trident, halberd;
|
||||||
|
|
||||||
/**These are not new mechs, just re-assignments for convenience.*/
|
/**
|
||||||
|
* These are not new mechs, just re-assignments for convenience.
|
||||||
|
*/
|
||||||
public static Mech starterDesktop, starterMobile;
|
public static Mech starterDesktop, starterMobile;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -171,7 +171,6 @@ public class Recipes implements ContentList{
|
|||||||
new Recipe(production, ProductionBlocks.oilextractor, new ItemStack(Items.titanium, 40), new ItemStack(Items.surgealloy, 40));*/
|
new Recipe(production, ProductionBlocks.oilextractor, new ItemStack(Items.titanium, 40), new ItemStack(Items.surgealloy, 40));*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//new Recipe(distribution, DistributionBlocks.massDriver, new ItemStack(Items.carbide, 1));
|
//new Recipe(distribution, DistributionBlocks.massDriver, new ItemStack(Items.carbide, 1));
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ package io.anuke.mindustry.content;
|
|||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
import io.anuke.mindustry.content.fx.EnvironmentFx;
|
import io.anuke.mindustry.content.fx.EnvironmentFx;
|
||||||
import io.anuke.mindustry.entities.StatusController.StatusEntry;
|
import io.anuke.mindustry.entities.StatusController.StatusEntry;
|
||||||
import io.anuke.mindustry.game.Content;
|
|
||||||
import io.anuke.mindustry.type.StatusEffect;
|
|
||||||
import io.anuke.mindustry.entities.Unit;
|
import io.anuke.mindustry.entities.Unit;
|
||||||
|
import io.anuke.mindustry.game.Content;
|
||||||
import io.anuke.mindustry.type.ContentList;
|
import io.anuke.mindustry.type.ContentList;
|
||||||
|
import io.anuke.mindustry.type.StatusEffect;
|
||||||
import io.anuke.ucore.core.Effects;
|
import io.anuke.ucore.core.Effects;
|
||||||
import io.anuke.ucore.core.Timers;
|
import io.anuke.ucore.core.Timers;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
|||||||
@@ -15,17 +15,22 @@ public class Blocks extends BlockList implements ContentList{
|
|||||||
public static Block air, spawn, blockpart, space, metalfloor, deepwater, water, lava, oil, stone, blackstone, dirt, sand, ice, snow, grass, shrub, rock, icerock, blackrock;
|
public static Block air, spawn, blockpart, space, metalfloor, deepwater, water, lava, oil, stone, blackstone, dirt, sand, ice, snow, grass, shrub, rock, icerock, blackrock;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(){
|
public void load(){
|
||||||
air = new Floor("air"){
|
air = new Floor("air"){
|
||||||
{
|
{
|
||||||
blend = false;
|
blend = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//don't draw
|
//don't draw
|
||||||
public void draw(Tile tile) {}
|
public void draw(Tile tile){
|
||||||
public void load() {}
|
}
|
||||||
public void init() {}
|
|
||||||
|
public void load(){
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(){
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
blockpart = new BlockPart();
|
blockpart = new BlockPart();
|
||||||
|
|||||||
@@ -28,6 +28,12 @@ import java.io.IOException;
|
|||||||
public class DebugBlocks extends BlockList implements ContentList{
|
public class DebugBlocks extends BlockList implements ContentList{
|
||||||
public static Block powerVoid, powerInfinite, itemSource, liquidSource, itemVoid;
|
public static Block powerVoid, powerInfinite, itemSource, liquidSource, itemVoid;
|
||||||
|
|
||||||
|
@Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true)
|
||||||
|
public static void setLiquidSourceLiquid(Player player, Tile tile, Liquid liquid){
|
||||||
|
LiquidSourceEntity entity = tile.entity();
|
||||||
|
entity.source = liquid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(){
|
public void load(){
|
||||||
powerVoid = new PowerBlock("powervoid"){
|
powerVoid = new PowerBlock("powervoid"){
|
||||||
@@ -53,6 +59,7 @@ public class DebugBlocks extends BlockList implements ContentList{
|
|||||||
{
|
{
|
||||||
hasItems = true;
|
hasItems = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(Tile tile){
|
public void update(Tile tile){
|
||||||
SorterEntity entity = tile.entity();
|
SorterEntity entity = tile.entity();
|
||||||
@@ -142,12 +149,6 @@ public class DebugBlocks extends BlockList implements ContentList{
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true)
|
|
||||||
public static void setLiquidSourceLiquid(Player player, Tile tile, Liquid liquid){
|
|
||||||
LiquidSourceEntity entity = tile.entity();
|
|
||||||
entity.source = liquid;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LiquidSourceEntity extends TileEntity{
|
class LiquidSourceEntity extends TileEntity{
|
||||||
public Liquid source = Liquids.water;
|
public Liquid source = Liquids.water;
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,13 @@ import io.anuke.mindustry.world.blocks.OreBlock;
|
|||||||
public class OreBlocks extends BlockList{
|
public class OreBlocks extends BlockList{
|
||||||
private static final ObjectMap<Item, ObjectMap<Block, Block>> oreBlockMap = new ObjectMap<>();
|
private static final ObjectMap<Item, ObjectMap<Block, Block>> oreBlockMap = new ObjectMap<>();
|
||||||
|
|
||||||
|
public static Block get(Block floor, Item item){
|
||||||
|
if(!oreBlockMap.containsKey(item)) throw new IllegalArgumentException("Item '" + item + "' is not an ore!");
|
||||||
|
if(!oreBlockMap.get(item).containsKey(floor))
|
||||||
|
throw new IllegalArgumentException("Block '" + floor.name + "' does not support ores!");
|
||||||
|
return oreBlockMap.get(item).get(floor);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(){
|
public void load(){
|
||||||
Item[] ores = {Items.tungsten, Items.lead, Items.coal, Items.titanium, Items.thorium};
|
Item[] ores = {Items.tungsten, Items.lead, Items.coal, Items.titanium, Items.thorium};
|
||||||
@@ -25,10 +32,4 @@ public class OreBlocks extends BlockList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Block get(Block floor, Item item){
|
|
||||||
if(!oreBlockMap.containsKey(item)) throw new IllegalArgumentException("Item '" + item + "' is not an ore!");
|
|
||||||
if(!oreBlockMap.get(item).containsKey(floor)) throw new IllegalArgumentException("Block '" + floor.name + "' does not support ores!");
|
|
||||||
return oreBlockMap.get(item).get(floor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ import io.anuke.ucore.util.Mathf;
|
|||||||
import io.anuke.ucore.util.Strings;
|
import io.anuke.ucore.util.Strings;
|
||||||
|
|
||||||
public class TurretBlocks extends BlockList implements ContentList{
|
public class TurretBlocks extends BlockList implements ContentList{
|
||||||
public static Block duo, /*scatter,*/ scorch, hail, wave, lancer, arc, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown;
|
public static Block duo, /*scatter,*/
|
||||||
|
scorch, hail, wave, lancer, arc, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void load(){
|
public void load(){
|
||||||
|
|||||||
@@ -25,8 +25,10 @@ import io.anuke.ucore.core.Effects;
|
|||||||
import io.anuke.ucore.function.Consumer;
|
import io.anuke.ucore.function.Consumer;
|
||||||
import io.anuke.ucore.util.Log;
|
import io.anuke.ucore.util.Log;
|
||||||
|
|
||||||
/**Loads all game content.
|
/**
|
||||||
* Call load() before doing anything with content.*/
|
* Loads all game content.
|
||||||
|
* Call load() before doing anything with content.
|
||||||
|
*/
|
||||||
public class ContentLoader{
|
public class ContentLoader{
|
||||||
private static boolean loaded = false;
|
private static boolean loaded = false;
|
||||||
private static ObjectSet<Array<? extends Content>> contentSet = new OrderedSet<>();
|
private static ObjectSet<Array<? extends Content>> contentSet = new OrderedSet<>();
|
||||||
@@ -94,7 +96,9 @@ public class ContentLoader {
|
|||||||
new Recipes(),
|
new Recipes(),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**Creates all content types.*/
|
/**
|
||||||
|
* Creates all content types.
|
||||||
|
*/
|
||||||
public static void load(){
|
public static void load(){
|
||||||
if(loaded){
|
if(loaded){
|
||||||
Log.info("Content already loaded, skipping.");
|
Log.info("Content already loaded, skipping.");
|
||||||
@@ -134,7 +138,9 @@ public class ContentLoader {
|
|||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Initializes all content with the specified function.*/
|
/**
|
||||||
|
* Initializes all content with the specified function.
|
||||||
|
*/
|
||||||
public static void initialize(Consumer<Content> callable){
|
public static void initialize(Consumer<Content> callable){
|
||||||
if(initialization.contains(callable)) return;
|
if(initialization.contains(callable)) return;
|
||||||
|
|
||||||
@@ -155,8 +161,10 @@ public class ContentLoader {
|
|||||||
return contentMap;
|
return contentMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Registers sync IDs for all types of sync entities.
|
/**
|
||||||
* Do not register units here!*/
|
* Registers sync IDs for all types of sync entities.
|
||||||
|
* Do not register units here!
|
||||||
|
*/
|
||||||
private static void registerTypes(){
|
private static void registerTypes(){
|
||||||
TypeTrait.registerType(Player.class, Player::new);
|
TypeTrait.registerType(Player.class, Player::new);
|
||||||
TypeTrait.registerType(ItemDrop.class, ItemDrop::new);
|
TypeTrait.registerType(ItemDrop.class, ItemDrop::new);
|
||||||
|
|||||||
@@ -30,12 +30,16 @@ import io.anuke.ucore.util.Atlas;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
/**Control module.
|
/**
|
||||||
|
* Control module.
|
||||||
* Handles all input, saving, keybinds and keybinds.
|
* Handles all input, saving, keybinds and keybinds.
|
||||||
* Should <i>not</i> handle any logic-critical state.
|
* Should <i>not</i> handle any logic-critical state.
|
||||||
* This class is not created in the headless server.*/
|
* This class is not created in the headless server.
|
||||||
|
*/
|
||||||
public class Control extends Module{
|
public class Control extends Module{
|
||||||
/**Minimum period of time between the same sound being played.*/
|
/**
|
||||||
|
* Minimum period of time between the same sound being played.
|
||||||
|
*/
|
||||||
private static final long minSoundPeriod = 100;
|
private static final long minSoundPeriod = 100;
|
||||||
|
|
||||||
private boolean hiscore = false;
|
private boolean hiscore = false;
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import io.anuke.mindustry.game.TeamInfo;
|
|||||||
import io.anuke.ucore.core.Events;
|
import io.anuke.ucore.core.Events;
|
||||||
|
|
||||||
public class GameState{
|
public class GameState{
|
||||||
private State state = State.menu;
|
|
||||||
|
|
||||||
public int wave = 1;
|
public int wave = 1;
|
||||||
public float wavetime;
|
public float wavetime;
|
||||||
public boolean gameOver = false;
|
public boolean gameOver = false;
|
||||||
@@ -18,6 +16,7 @@ public class GameState{
|
|||||||
public boolean friendlyFire;
|
public boolean friendlyFire;
|
||||||
public WaveSpawner spawner = new WaveSpawner();
|
public WaveSpawner spawner = new WaveSpawner();
|
||||||
public TeamInfo teams = new TeamInfo();
|
public TeamInfo teams = new TeamInfo();
|
||||||
|
private State state = State.menu;
|
||||||
|
|
||||||
public void set(State astate){
|
public void set(State astate){
|
||||||
Events.fire(StateChangeEvent.class, state, astate);
|
Events.fire(StateChangeEvent.class, state, astate);
|
||||||
|
|||||||
@@ -24,12 +24,14 @@ import io.anuke.ucore.modules.Module;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
/**Logic module.
|
/**
|
||||||
|
* Logic module.
|
||||||
* Handles all logic for entities and waves.
|
* Handles all logic for entities and waves.
|
||||||
* Handles game state events.
|
* Handles game state events.
|
||||||
* Does not store any game state itself.
|
* Does not store any game state itself.
|
||||||
*
|
* <p>
|
||||||
* This class should <i>not</i> call any outside methods to change state of modules, but instead fire events.*/
|
* This class should <i>not</i> call any outside methods to change state of modules, but instead fire events.
|
||||||
|
*/
|
||||||
public class Logic extends Module{
|
public class Logic extends Module{
|
||||||
public boolean doUpdate = true;
|
public boolean doUpdate = true;
|
||||||
|
|
||||||
@@ -137,7 +139,8 @@ public class Logic extends Module {
|
|||||||
runWave();
|
runWave();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!Entities.defaultGroup().isEmpty()) throw new RuntimeException("Do not add anything to the default group!");
|
if(!Entities.defaultGroup().isEmpty())
|
||||||
|
throw new RuntimeException("Do not add anything to the default group!");
|
||||||
|
|
||||||
Entities.update(bulletGroup);
|
Entities.update(bulletGroup);
|
||||||
for(EntityGroup group : unitGroups){
|
for(EntityGroup group : unitGroups){
|
||||||
|
|||||||
@@ -41,33 +41,59 @@ public class NetClient extends Module {
|
|||||||
private final static float playerSyncTime = 2;
|
private final static float playerSyncTime = 2;
|
||||||
|
|
||||||
private Timer timer = new Timer(5);
|
private Timer timer = new Timer(5);
|
||||||
/**Whether the client is currently connecting.*/
|
/**
|
||||||
|
* Whether the client is currently connecting.
|
||||||
|
*/
|
||||||
private boolean connecting = false;
|
private boolean connecting = false;
|
||||||
/**If true, no message will be shown on disconnect.*/
|
/**
|
||||||
|
* If true, no message will be shown on disconnect.
|
||||||
|
*/
|
||||||
private boolean quiet = false;
|
private boolean quiet = false;
|
||||||
/**Counter for data timeout.*/
|
/**
|
||||||
|
* Counter for data timeout.
|
||||||
|
*/
|
||||||
private float timeoutTime = 0f;
|
private float timeoutTime = 0f;
|
||||||
/**Last sent client snapshot ID.*/
|
/**
|
||||||
|
* Last sent client snapshot ID.
|
||||||
|
*/
|
||||||
private int lastSent;
|
private int lastSent;
|
||||||
|
|
||||||
/**Last snapshot ID recieved.*/
|
/**
|
||||||
|
* Last snapshot ID recieved.
|
||||||
|
*/
|
||||||
private int lastSnapshotBaseID = -1;
|
private int lastSnapshotBaseID = -1;
|
||||||
/**Last snapshot recieved.*/
|
/**
|
||||||
|
* Last snapshot recieved.
|
||||||
|
*/
|
||||||
private byte[] lastSnapshotBase;
|
private byte[] lastSnapshotBase;
|
||||||
/**Current snapshot that is being built from chinks.*/
|
/**
|
||||||
|
* Current snapshot that is being built from chinks.
|
||||||
|
*/
|
||||||
private byte[] currentSnapshot;
|
private byte[] currentSnapshot;
|
||||||
/**Array of recieved chunk statuses.*/
|
/**
|
||||||
|
* Array of recieved chunk statuses.
|
||||||
|
*/
|
||||||
private boolean[] recievedChunks;
|
private boolean[] recievedChunks;
|
||||||
/**Counter of how many chunks have been recieved.*/
|
/**
|
||||||
|
* Counter of how many chunks have been recieved.
|
||||||
|
*/
|
||||||
private int recievedChunkCounter;
|
private int recievedChunkCounter;
|
||||||
/**ID of snapshot that is currently being constructed.*/
|
/**
|
||||||
|
* ID of snapshot that is currently being constructed.
|
||||||
|
*/
|
||||||
private int currentSnapshotID = -1;
|
private int currentSnapshotID = -1;
|
||||||
|
|
||||||
/**Decoder for uncompressing snapshots.*/
|
/**
|
||||||
|
* Decoder for uncompressing snapshots.
|
||||||
|
*/
|
||||||
private DEZDecoder decoder = new DEZDecoder();
|
private DEZDecoder decoder = new DEZDecoder();
|
||||||
/**List of entities that were removed, and need not be added while syncing.*/
|
/**
|
||||||
|
* List of entities that were removed, and need not be added while syncing.
|
||||||
|
*/
|
||||||
private IntSet removed = new IntSet();
|
private IntSet removed = new IntSet();
|
||||||
/**Byte stream for reading in snapshots.*/
|
/**
|
||||||
|
* Byte stream for reading in snapshots.
|
||||||
|
*/
|
||||||
private ReusableByteArrayInputStream byteStream = new ReusableByteArrayInputStream();
|
private ReusableByteArrayInputStream byteStream = new ReusableByteArrayInputStream();
|
||||||
private DataInputStream dataStream = new DataInputStream(byteStream);
|
private DataInputStream dataStream = new DataInputStream(byteStream);
|
||||||
|
|
||||||
@@ -145,6 +171,166 @@ public class NetClient extends Module {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Remote(variants = Variant.one, priority = PacketPriority.high)
|
||||||
|
public static void onKick(KickReason reason){
|
||||||
|
netClient.disconnectQuietly();
|
||||||
|
state.set(State.menu);
|
||||||
|
if(!reason.quiet) ui.showError("$text.server.kicked." + reason.name());
|
||||||
|
ui.loadfrag.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(variants = Variant.one)
|
||||||
|
public static void onPositionSet(float x, float y){
|
||||||
|
players[0].x = x;
|
||||||
|
players[0].y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(variants = Variant.one)
|
||||||
|
public static void onTraceInfo(TraceInfo info){
|
||||||
|
Player player = playerGroup.getByID(info.playerid);
|
||||||
|
ui.traces.show(player, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote
|
||||||
|
public static void onPlayerDisconnect(int playerid){
|
||||||
|
playerGroup.removeByID(playerid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
||||||
|
public static void onSnapshot(byte[] chunk, int snapshotID, short chunkID, int totalLength, int base){
|
||||||
|
if(NetServer.showSnapshotSize)
|
||||||
|
Log.info("Recieved snapshot: len {0} ID {1} chunkID {2} totalLength {3} base {4} client-base {5}", chunk.length, snapshotID, chunkID, totalLength, base, netClient.lastSnapshotBaseID);
|
||||||
|
|
||||||
|
//skip snapshot IDs that have already been recieved OR snapshots that are too far in front
|
||||||
|
if(snapshotID < netClient.lastSnapshotBaseID || base != netClient.lastSnapshotBaseID){
|
||||||
|
if(NetServer.showSnapshotSize) Log.info("//SKIP SNAPSHOT");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
byte[] snapshot;
|
||||||
|
|
||||||
|
//total length exceeds that needed to hold one snapshot, therefore, it is split into chunks
|
||||||
|
if(totalLength > NetServer.maxSnapshotSize){
|
||||||
|
//total amount of chunks to recieve
|
||||||
|
int totalChunks = Mathf.ceil((float) totalLength / NetServer.maxSnapshotSize);
|
||||||
|
|
||||||
|
//reset status when a new snapshot sending begins
|
||||||
|
if(netClient.currentSnapshotID != snapshotID){
|
||||||
|
netClient.currentSnapshotID = snapshotID;
|
||||||
|
netClient.currentSnapshot = new byte[totalLength];
|
||||||
|
netClient.recievedChunkCounter = 0;
|
||||||
|
netClient.recievedChunks = new boolean[totalChunks];
|
||||||
|
}
|
||||||
|
|
||||||
|
//if this chunk hasn't been recieved yet...
|
||||||
|
if(!netClient.recievedChunks[chunkID]){
|
||||||
|
netClient.recievedChunks[chunkID] = true;
|
||||||
|
netClient.recievedChunkCounter++; //update recieved status
|
||||||
|
//copy the recieved bytes into the holding array
|
||||||
|
System.arraycopy(chunk, 0, netClient.currentSnapshot, chunkID * NetServer.maxSnapshotSize,
|
||||||
|
Math.min(NetServer.maxSnapshotSize, totalLength - chunkID * NetServer.maxSnapshotSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
//when all chunks have been recieved, begin
|
||||||
|
if(netClient.recievedChunkCounter >= totalChunks){
|
||||||
|
snapshot = netClient.currentSnapshot;
|
||||||
|
}else{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
snapshot = chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(NetServer.showSnapshotSize)
|
||||||
|
Log.info("Finished recieving snapshot ID {0} length {1}", snapshotID, chunk.length);
|
||||||
|
|
||||||
|
byte[] result;
|
||||||
|
int length;
|
||||||
|
if(base == -1){ //fresh snapshot
|
||||||
|
result = snapshot;
|
||||||
|
length = snapshot.length;
|
||||||
|
netClient.lastSnapshotBase = Arrays.copyOf(snapshot, snapshot.length);
|
||||||
|
}else{ //otherwise, last snapshot must not be null, decode it
|
||||||
|
if(NetServer.showSnapshotSize)
|
||||||
|
Log.info("Base size: {0} Patch size: {1}", netClient.lastSnapshotBase.length, snapshot.length);
|
||||||
|
netClient.decoder.init(netClient.lastSnapshotBase, snapshot);
|
||||||
|
result = netClient.decoder.decode();
|
||||||
|
length = netClient.decoder.getDecodedLength();
|
||||||
|
//set last snapshot to a copy to prevent issues
|
||||||
|
netClient.lastSnapshotBase = Arrays.copyOf(result, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
netClient.lastSnapshotBaseID = snapshotID;
|
||||||
|
|
||||||
|
//set stream bytes to begin snapshot reaeding
|
||||||
|
netClient.byteStream.setBytes(result, 0, length);
|
||||||
|
|
||||||
|
//get data input for reading from the stream
|
||||||
|
DataInputStream input = netClient.dataStream;
|
||||||
|
|
||||||
|
//read wave info
|
||||||
|
state.wavetime = input.readFloat();
|
||||||
|
state.wave = input.readInt();
|
||||||
|
|
||||||
|
byte cores = input.readByte();
|
||||||
|
for(int i = 0; i < cores; i++){
|
||||||
|
int pos = input.readInt();
|
||||||
|
world.tile(pos).entity.items.read(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
long timestamp = input.readLong();
|
||||||
|
|
||||||
|
byte totalGroups = input.readByte();
|
||||||
|
//for each group...
|
||||||
|
for(int i = 0; i < totalGroups; i++){
|
||||||
|
//read group info
|
||||||
|
byte groupID = input.readByte();
|
||||||
|
short amount = input.readShort();
|
||||||
|
|
||||||
|
EntityGroup group = Entities.getGroup(groupID);
|
||||||
|
|
||||||
|
//go through each entity
|
||||||
|
for(int j = 0; j < amount; j++){
|
||||||
|
int position = netClient.byteStream.position(); //save position to check read/write correctness
|
||||||
|
int id = input.readInt();
|
||||||
|
byte typeID = input.readByte();
|
||||||
|
|
||||||
|
SyncTrait entity = (SyncTrait) group.getByID(id);
|
||||||
|
boolean add = false;
|
||||||
|
|
||||||
|
//entity must not be added yet, so create it
|
||||||
|
if(entity == null){
|
||||||
|
entity = (SyncTrait) TypeTrait.getTypeByID(typeID).get(); //create entity from supplier
|
||||||
|
entity.resetID(id);
|
||||||
|
if(!netClient.isEntityUsed(entity.getID())){
|
||||||
|
add = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//read the entity
|
||||||
|
entity.read(input, timestamp);
|
||||||
|
|
||||||
|
byte readLength = input.readByte();
|
||||||
|
if(netClient.byteStream.position() - position - 1 != readLength){
|
||||||
|
throw new RuntimeException("Error reading entity of type '" + group.getType() + "': Read length mismatch [write=" + readLength + ", read=" + (netClient.byteStream.position() - position - 1) + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(add){
|
||||||
|
entity.add();
|
||||||
|
netClient.addRemovedEntity(entity.getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//confirm that snapshot has been recieved
|
||||||
|
netClient.lastSnapshotBaseID = snapshotID;
|
||||||
|
|
||||||
|
}catch(Exception e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void update(){
|
||||||
if(!Net.client()) return;
|
if(!Net.client()) return;
|
||||||
@@ -224,161 +410,4 @@ public class NetClient extends Module {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(variants = Variant.one, priority = PacketPriority.high)
|
|
||||||
public static void onKick(KickReason reason){
|
|
||||||
netClient.disconnectQuietly();
|
|
||||||
state.set(State.menu);
|
|
||||||
if(!reason.quiet) ui.showError("$text.server.kicked." + reason.name());
|
|
||||||
ui.loadfrag.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(variants = Variant.one)
|
|
||||||
public static void onPositionSet(float x, float y){
|
|
||||||
players[0].x = x;
|
|
||||||
players[0].y = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(variants = Variant.one)
|
|
||||||
public static void onTraceInfo(TraceInfo info){
|
|
||||||
Player player = playerGroup.getByID(info.playerid);
|
|
||||||
ui.traces.show(player, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote
|
|
||||||
public static void onPlayerDisconnect(int playerid){
|
|
||||||
playerGroup.removeByID(playerid);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
|
||||||
public static void onSnapshot(byte[] chunk, int snapshotID, short chunkID, int totalLength, int base){
|
|
||||||
if(NetServer.showSnapshotSize) Log.info("Recieved snapshot: len {0} ID {1} chunkID {2} totalLength {3} base {4} client-base {5}", chunk.length, snapshotID, chunkID, totalLength, base, netClient.lastSnapshotBaseID);
|
|
||||||
|
|
||||||
//skip snapshot IDs that have already been recieved OR snapshots that are too far in front
|
|
||||||
if(snapshotID < netClient.lastSnapshotBaseID || base != netClient.lastSnapshotBaseID){
|
|
||||||
if(NetServer.showSnapshotSize) Log.info("//SKIP SNAPSHOT");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
byte[] snapshot;
|
|
||||||
|
|
||||||
//total length exceeds that needed to hold one snapshot, therefore, it is split into chunks
|
|
||||||
if(totalLength > NetServer.maxSnapshotSize) {
|
|
||||||
//total amount of chunks to recieve
|
|
||||||
int totalChunks = Mathf.ceil((float) totalLength / NetServer.maxSnapshotSize);
|
|
||||||
|
|
||||||
//reset status when a new snapshot sending begins
|
|
||||||
if (netClient.currentSnapshotID != snapshotID) {
|
|
||||||
netClient.currentSnapshotID = snapshotID;
|
|
||||||
netClient.currentSnapshot = new byte[totalLength];
|
|
||||||
netClient.recievedChunkCounter = 0;
|
|
||||||
netClient.recievedChunks = new boolean[totalChunks];
|
|
||||||
}
|
|
||||||
|
|
||||||
//if this chunk hasn't been recieved yet...
|
|
||||||
if (!netClient.recievedChunks[chunkID]) {
|
|
||||||
netClient.recievedChunks[chunkID] = true;
|
|
||||||
netClient.recievedChunkCounter ++; //update recieved status
|
|
||||||
//copy the recieved bytes into the holding array
|
|
||||||
System.arraycopy(chunk, 0, netClient.currentSnapshot, chunkID * NetServer.maxSnapshotSize,
|
|
||||||
Math.min(NetServer.maxSnapshotSize, totalLength - chunkID * NetServer.maxSnapshotSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
//when all chunks have been recieved, begin
|
|
||||||
if(netClient.recievedChunkCounter >= totalChunks){
|
|
||||||
snapshot = netClient.currentSnapshot;
|
|
||||||
}else{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
snapshot = chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(NetServer.showSnapshotSize) Log.info("Finished recieving snapshot ID {0} length {1}", snapshotID, chunk.length);
|
|
||||||
|
|
||||||
byte[] result;
|
|
||||||
int length;
|
|
||||||
if (base == -1) { //fresh snapshot
|
|
||||||
result = snapshot;
|
|
||||||
length = snapshot.length;
|
|
||||||
netClient.lastSnapshotBase = Arrays.copyOf(snapshot, snapshot.length);
|
|
||||||
} else { //otherwise, last snapshot must not be null, decode it
|
|
||||||
if(NetServer.showSnapshotSize) Log.info("Base size: {0} Patch size: {1}", netClient.lastSnapshotBase.length, snapshot.length);
|
|
||||||
netClient.decoder.init(netClient.lastSnapshotBase, snapshot);
|
|
||||||
result = netClient.decoder.decode();
|
|
||||||
length = netClient.decoder.getDecodedLength();
|
|
||||||
//set last snapshot to a copy to prevent issues
|
|
||||||
netClient.lastSnapshotBase = Arrays.copyOf(result, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
netClient.lastSnapshotBaseID = snapshotID;
|
|
||||||
|
|
||||||
//set stream bytes to begin snapshot reaeding
|
|
||||||
netClient.byteStream.setBytes(result, 0, length);
|
|
||||||
|
|
||||||
//get data input for reading from the stream
|
|
||||||
DataInputStream input = netClient.dataStream;
|
|
||||||
|
|
||||||
//read wave info
|
|
||||||
state.wavetime = input.readFloat();
|
|
||||||
state.wave = input.readInt();
|
|
||||||
|
|
||||||
byte cores = input.readByte();
|
|
||||||
for (int i = 0; i < cores; i++) {
|
|
||||||
int pos = input.readInt();
|
|
||||||
world.tile(pos).entity.items.read(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
long timestamp = input.readLong();
|
|
||||||
|
|
||||||
byte totalGroups = input.readByte();
|
|
||||||
//for each group...
|
|
||||||
for (int i = 0; i < totalGroups; i++) {
|
|
||||||
//read group info
|
|
||||||
byte groupID = input.readByte();
|
|
||||||
short amount = input.readShort();
|
|
||||||
|
|
||||||
EntityGroup group = Entities.getGroup(groupID);
|
|
||||||
|
|
||||||
//go through each entity
|
|
||||||
for (int j = 0; j < amount; j++) {
|
|
||||||
int position = netClient.byteStream.position(); //save position to check read/write correctness
|
|
||||||
int id = input.readInt();
|
|
||||||
byte typeID = input.readByte();
|
|
||||||
|
|
||||||
SyncTrait entity = (SyncTrait) group.getByID(id);
|
|
||||||
boolean add = false;
|
|
||||||
|
|
||||||
//entity must not be added yet, so create it
|
|
||||||
if(entity == null){
|
|
||||||
entity = (SyncTrait) TypeTrait.getTypeByID(typeID).get(); //create entity from supplier
|
|
||||||
entity.resetID(id);
|
|
||||||
if(!netClient.isEntityUsed(entity.getID())){
|
|
||||||
add = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//read the entity
|
|
||||||
entity.read(input, timestamp);
|
|
||||||
|
|
||||||
byte readLength = input.readByte();
|
|
||||||
if(netClient.byteStream.position() - position - 1 != readLength){
|
|
||||||
throw new RuntimeException("Error reading entity of type '"+ group.getType() + "': Read length mismatch [write=" + readLength + ", read=" + (netClient.byteStream.position() - position - 1)+ "]");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(add){
|
|
||||||
entity.add();
|
|
||||||
netClient.addRemovedEntity(entity.getID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//confirm that snapshot has been recieved
|
|
||||||
netClient.lastSnapshotBaseID = snapshotID;
|
|
||||||
|
|
||||||
}catch (Exception e){
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -45,20 +45,30 @@ public class NetServer extends Module{
|
|||||||
private final static byte[] reusableSnapArray = new byte[maxSnapshotSize];
|
private final static byte[] reusableSnapArray = new byte[maxSnapshotSize];
|
||||||
private final static float serverSyncTime = 4, kickDuration = 30 * 1000;
|
private final static float serverSyncTime = 4, kickDuration = 30 * 1000;
|
||||||
private final static Vector2 vector = new Vector2();
|
private final static Vector2 vector = new Vector2();
|
||||||
/**If a play goes away of their server-side coordinates by this distance, they get teleported back.*/
|
/**
|
||||||
|
* If a play goes away of their server-side coordinates by this distance, they get teleported back.
|
||||||
|
*/
|
||||||
private final static float correctDist = 16f;
|
private final static float correctDist = 16f;
|
||||||
|
|
||||||
public final Administration admins = new Administration();
|
public final Administration admins = new Administration();
|
||||||
|
|
||||||
/**Maps connection IDs to players.*/
|
/**
|
||||||
|
* Maps connection IDs to players.
|
||||||
|
*/
|
||||||
private IntMap<Player> connections = new IntMap<>();
|
private IntMap<Player> connections = new IntMap<>();
|
||||||
private boolean closing = false;
|
private boolean closing = false;
|
||||||
|
|
||||||
/**Stream for writing player sync data to.*/
|
/**
|
||||||
|
* Stream for writing player sync data to.
|
||||||
|
*/
|
||||||
private CountableByteArrayOutputStream syncStream = new CountableByteArrayOutputStream();
|
private CountableByteArrayOutputStream syncStream = new CountableByteArrayOutputStream();
|
||||||
/**Data stream for writing player sync data to.*/
|
/**
|
||||||
|
* Data stream for writing player sync data to.
|
||||||
|
*/
|
||||||
private DataOutputStream dataStream = new DataOutputStream(syncStream);
|
private DataOutputStream dataStream = new DataOutputStream(syncStream);
|
||||||
/**Encoder for computing snapshot deltas.*/
|
/**
|
||||||
|
* Encoder for computing snapshot deltas.
|
||||||
|
*/
|
||||||
private DEZEncoder encoder = new DEZEncoder();
|
private DEZEncoder encoder = new DEZEncoder();
|
||||||
|
|
||||||
public NetServer(){
|
public NetServer(){
|
||||||
@@ -238,6 +248,86 @@ public class NetServer extends Module{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a raw byte[] snapshot to a client, splitting up into chunks when needed.
|
||||||
|
*/
|
||||||
|
private static void sendSplitSnapshot(int userid, byte[] bytes, int snapshotID, int base){
|
||||||
|
if(bytes.length < maxSnapshotSize){
|
||||||
|
Call.onSnapshot(userid, bytes, snapshotID, (short) 0, bytes.length, base);
|
||||||
|
}else{
|
||||||
|
int remaining = bytes.length;
|
||||||
|
int offset = 0;
|
||||||
|
int chunkid = 0;
|
||||||
|
while(remaining > 0){
|
||||||
|
int used = Math.min(remaining, maxSnapshotSize);
|
||||||
|
byte[] toSend;
|
||||||
|
//re-use sent byte arrays when possible
|
||||||
|
if(used == maxSnapshotSize){
|
||||||
|
toSend = reusableSnapArray;
|
||||||
|
System.arraycopy(bytes, offset, toSend, 0, Math.min(offset + maxSnapshotSize, bytes.length) - offset);
|
||||||
|
}else{
|
||||||
|
toSend = Arrays.copyOfRange(bytes, offset, Math.min(offset + maxSnapshotSize, bytes.length));
|
||||||
|
}
|
||||||
|
Call.onSnapshot(userid, toSend, snapshotID, (short) chunkid, bytes.length, base);
|
||||||
|
|
||||||
|
remaining -= used;
|
||||||
|
offset += used;
|
||||||
|
chunkid++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void onDisconnect(Player player){
|
||||||
|
Call.sendMessage("[accent]" + player.name + " has disconnected.");
|
||||||
|
Call.onPlayerDisconnect(player.id);
|
||||||
|
player.remove();
|
||||||
|
netServer.connections.remove(player.con.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(targets = Loc.client, called = Loc.server)
|
||||||
|
public static void onAdminRequest(Player player, Player other, AdminAction action){
|
||||||
|
|
||||||
|
if(!player.isAdmin){
|
||||||
|
Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.",
|
||||||
|
player.name, player.con.address);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(other == null || (other.isAdmin && other != player)){ //fun fact: this means you can ban yourself
|
||||||
|
Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(action == AdminAction.wave){
|
||||||
|
//no verification is done, so admins can hypothetically spam waves
|
||||||
|
//not a real issue, because server owners may want to do just that
|
||||||
|
state.wavetime = 0f;
|
||||||
|
}else if(action == AdminAction.ban){
|
||||||
|
netServer.admins.banPlayerIP(other.con.address);
|
||||||
|
netServer.kick(other.con.id, KickReason.banned);
|
||||||
|
Log.info("&lc{0} has banned {1}.", player.name, other.name);
|
||||||
|
}else if(action == AdminAction.kick){
|
||||||
|
netServer.kick(other.con.id, KickReason.kick);
|
||||||
|
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
|
||||||
|
}else if(action == AdminAction.trace){
|
||||||
|
//TODO
|
||||||
|
if(player.con != null){
|
||||||
|
Call.onTraceInfo(player.con.id, netServer.admins.getTraceByID(other.uuid));
|
||||||
|
}else{
|
||||||
|
NetClient.onTraceInfo(netServer.admins.getTraceByID(other.uuid));
|
||||||
|
}
|
||||||
|
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(targets = Loc.client)
|
||||||
|
public static void connectConfirm(Player player){
|
||||||
|
player.add();
|
||||||
|
player.con.hasConnected = true;
|
||||||
|
Call.sendMessage("[accent]" + player.name + " has connected.");
|
||||||
|
Log.info("&y{0} has connected.", player.name);
|
||||||
|
}
|
||||||
|
|
||||||
public void update(){
|
public void update(){
|
||||||
if(!headless && !closing && Net.server() && state.is(State.menu)){
|
if(!headless && !closing && Net.server() && state.is(State.menu)){
|
||||||
closing = true;
|
closing = true;
|
||||||
@@ -344,7 +434,8 @@ public class NetServer extends Module{
|
|||||||
|
|
||||||
//if the player hasn't acknowledged that it has recieved the packet, send the same thing again
|
//if the player hasn't acknowledged that it has recieved the packet, send the same thing again
|
||||||
if(connection.currentBaseID < connection.lastSentSnapshotID){
|
if(connection.currentBaseID < connection.lastSentSnapshotID){
|
||||||
if(showSnapshotSize) Log.info("Re-sending snapshot: {0} bytes, ID {1} base {2} baselength {3}", connection.lastSentSnapshot.length, connection.lastSentSnapshotID, connection.lastSentBase, connection.currentBaseSnapshot.length);
|
if(showSnapshotSize)
|
||||||
|
Log.info("Re-sending snapshot: {0} bytes, ID {1} base {2} baselength {3}", connection.lastSentSnapshot.length, connection.lastSentSnapshotID, connection.lastSentBase, connection.currentBaseSnapshot.length);
|
||||||
sendSplitSnapshot(connection.id, connection.lastSentSnapshot, connection.lastSentSnapshotID, connection.lastSentBase);
|
sendSplitSnapshot(connection.id, connection.lastSentSnapshot, connection.lastSentSnapshotID, connection.lastSentBase);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -409,7 +500,8 @@ public class NetServer extends Module{
|
|||||||
dataStream.writeByte(((SyncTrait) entity).getTypeID()); //write type ID
|
dataStream.writeByte(((SyncTrait) entity).getTypeID()); //write type ID
|
||||||
((SyncTrait) entity).write(dataStream); //write entity
|
((SyncTrait) entity).write(dataStream); //write entity
|
||||||
int length = syncStream.position() - position; //length must always be less than 127 bytes
|
int length = syncStream.position() - position; //length must always be less than 127 bytes
|
||||||
if(length > 127) throw new RuntimeException("Write size for entity of type " + group.getType() + " must not exceed 127!");
|
if(length > 127)
|
||||||
|
throw new RuntimeException("Write size for entity of type " + group.getType() + " must not exceed 127!");
|
||||||
dataStream.writeByte(length);
|
dataStream.writeByte(length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -433,7 +525,8 @@ public class NetServer extends Module{
|
|||||||
|
|
||||||
//send diff, otherwise
|
//send diff, otherwise
|
||||||
byte[] diff = ByteDeltaEncoder.toDiff(new ByteMatcherHash(connection.currentBaseSnapshot, bytes), encoder);
|
byte[] diff = ByteDeltaEncoder.toDiff(new ByteMatcherHash(connection.currentBaseSnapshot, bytes), encoder);
|
||||||
if(showSnapshotSize) Log.info("Shrank snapshot: {0} -> {1}, Base {2} ID {3} base length = {4}", bytes.length, diff.length, connection.currentBaseID, connection.currentBaseID + 1, connection.currentBaseSnapshot.length);
|
if(showSnapshotSize)
|
||||||
|
Log.info("Shrank snapshot: {0} -> {1}, Base {2} ID {3} base length = {4}", bytes.length, diff.length, connection.currentBaseID, connection.currentBaseID + 1, connection.currentBaseSnapshot.length);
|
||||||
sendSplitSnapshot(connection.id, diff, connection.currentBaseID + 1, connection.currentBaseID);
|
sendSplitSnapshot(connection.id, diff, connection.currentBaseID + 1, connection.currentBaseID);
|
||||||
connection.lastSentSnapshot = diff;
|
connection.lastSentSnapshot = diff;
|
||||||
connection.lastSentSnapshotID = connection.currentBaseID + 1;
|
connection.lastSentSnapshotID = connection.currentBaseID + 1;
|
||||||
@@ -445,82 +538,4 @@ public class NetServer extends Module{
|
|||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sends a raw byte[] snapshot to a client, splitting up into chunks when needed.*/
|
|
||||||
private static void sendSplitSnapshot(int userid, byte[] bytes, int snapshotID, int base){
|
|
||||||
if(bytes.length < maxSnapshotSize){
|
|
||||||
Call.onSnapshot(userid, bytes, snapshotID, (short)0, bytes.length, base);
|
|
||||||
}else{
|
|
||||||
int remaining = bytes.length;
|
|
||||||
int offset = 0;
|
|
||||||
int chunkid = 0;
|
|
||||||
while(remaining > 0){
|
|
||||||
int used = Math.min(remaining, maxSnapshotSize);
|
|
||||||
byte[] toSend;
|
|
||||||
//re-use sent byte arrays when possible
|
|
||||||
if(used == maxSnapshotSize){
|
|
||||||
toSend = reusableSnapArray;
|
|
||||||
System.arraycopy(bytes, offset, toSend, 0, Math.min(offset + maxSnapshotSize, bytes.length) - offset);
|
|
||||||
}else {
|
|
||||||
toSend = Arrays.copyOfRange(bytes, offset, Math.min(offset + maxSnapshotSize, bytes.length));
|
|
||||||
}
|
|
||||||
Call.onSnapshot(userid, toSend, snapshotID, (short)chunkid, bytes.length, base);
|
|
||||||
|
|
||||||
remaining -= used;
|
|
||||||
offset += used;
|
|
||||||
chunkid ++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void onDisconnect(Player player){
|
|
||||||
Call.sendMessage("[accent]" + player.name + " has disconnected.");
|
|
||||||
Call.onPlayerDisconnect(player.id);
|
|
||||||
player.remove();
|
|
||||||
netServer.connections.remove(player.con.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(targets = Loc.client, called = Loc.server)
|
|
||||||
public static void onAdminRequest(Player player, Player other, AdminAction action){
|
|
||||||
|
|
||||||
if(!player.isAdmin){
|
|
||||||
Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.",
|
|
||||||
player.name, player.con.address);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(other == null || (other.isAdmin && other != player)){ //fun fact: this means you can ban yourself
|
|
||||||
Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(action == AdminAction.wave) {
|
|
||||||
//no verification is done, so admins can hypothetically spam waves
|
|
||||||
//not a real issue, because server owners may want to do just that
|
|
||||||
state.wavetime = 0f;
|
|
||||||
}else if(action == AdminAction.ban){
|
|
||||||
netServer.admins.banPlayerIP(other.con.address);
|
|
||||||
netServer.kick(other.con.id, KickReason.banned);
|
|
||||||
Log.info("&lc{0} has banned {1}.", player.name, other.name);
|
|
||||||
}else if(action == AdminAction.kick){
|
|
||||||
netServer.kick(other.con.id, KickReason.kick);
|
|
||||||
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
|
|
||||||
}else if(action == AdminAction.trace){
|
|
||||||
//TODO
|
|
||||||
if(player.con != null) {
|
|
||||||
Call.onTraceInfo(player.con.id, netServer.admins.getTraceByID(other.uuid));
|
|
||||||
}else{
|
|
||||||
NetClient.onTraceInfo(netServer.admins.getTraceByID(other.uuid));
|
|
||||||
}
|
|
||||||
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(targets = Loc.client)
|
|
||||||
public static void connectConfirm(Player player){
|
|
||||||
player.add();
|
|
||||||
player.con.hasConnected = true;
|
|
||||||
Call.sendMessage("[accent]" + player.name + " has connected.");
|
|
||||||
Log.info("&y{0} has connected.", player.name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,44 +12,101 @@ import java.util.Locale;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
public abstract class Platform{
|
public abstract class Platform{
|
||||||
/**Each separate game platform should set this instance to their own implementation.*/
|
/**
|
||||||
public static Platform instance = new Platform() {};
|
* Each separate game platform should set this instance to their own implementation.
|
||||||
|
*/
|
||||||
|
public static Platform instance = new Platform(){
|
||||||
|
};
|
||||||
|
|
||||||
/**Format the date using the default date formatter.*/
|
/**
|
||||||
public String format(Date date){return "invalid";}
|
* Format the date using the default date formatter.
|
||||||
/**Format a number by adding in commas or periods where needed.*/
|
*/
|
||||||
public String format(int number){return "invalid";}
|
public String format(Date date){
|
||||||
/**Show a native error dialog.*/
|
return "invalid";
|
||||||
public void showError(String text){}
|
}
|
||||||
/**Add a text input dialog that should show up after the field is tapped.*/
|
|
||||||
|
/**
|
||||||
|
* Format a number by adding in commas or periods where needed.
|
||||||
|
*/
|
||||||
|
public String format(int number){
|
||||||
|
return "invalid";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a native error dialog.
|
||||||
|
*/
|
||||||
|
public void showError(String text){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a text input dialog that should show up after the field is tapped.
|
||||||
|
*/
|
||||||
public void addDialog(TextField field){
|
public void addDialog(TextField field){
|
||||||
addDialog(field, 16);
|
addDialog(field, 16);
|
||||||
}
|
}
|
||||||
/**See addDialog().*/
|
|
||||||
public void addDialog(TextField field, int maxLength){}
|
/**
|
||||||
/**Update discord RPC.*/
|
* See addDialog().
|
||||||
public void updateRPC(){}
|
*/
|
||||||
/**Called when the game is exited.*/
|
public void addDialog(TextField field, int maxLength){
|
||||||
public void onGameExit(){}
|
}
|
||||||
/**Open donation dialog. Currently android only.*/
|
|
||||||
public void openDonations(){}
|
/**
|
||||||
/**Whether donating is supported.*/
|
* Update discord RPC.
|
||||||
|
*/
|
||||||
|
public void updateRPC(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the game is exited.
|
||||||
|
*/
|
||||||
|
public void onGameExit(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open donation dialog. Currently android only.
|
||||||
|
*/
|
||||||
|
public void openDonations(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether donating is supported.
|
||||||
|
*/
|
||||||
public boolean canDonate(){
|
public boolean canDonate(){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
/**Whether discord RPC is supported.*/
|
|
||||||
public boolean hasDiscord(){return true;}
|
/**
|
||||||
/**Return the localized name for the locale. This is basically a workaround for GWT not supporting getName().*/
|
* Whether discord RPC is supported.
|
||||||
|
*/
|
||||||
|
public boolean hasDiscord(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the localized name for the locale. This is basically a workaround for GWT not supporting getName().
|
||||||
|
*/
|
||||||
public String getLocaleName(Locale locale){
|
public String getLocaleName(Locale locale){
|
||||||
return locale.toString();
|
return locale.toString();
|
||||||
}
|
}
|
||||||
/**Whether joining games is supported.*/
|
|
||||||
|
/**
|
||||||
|
* Whether joining games is supported.
|
||||||
|
*/
|
||||||
public boolean canJoinGame(){
|
public boolean canJoinGame(){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/**Whether debug mode is enabled.*/
|
|
||||||
public boolean isDebug(){return false;}
|
/**
|
||||||
/**Must be a base64 string 8 bytes in length.*/
|
* Whether debug mode is enabled.
|
||||||
|
*/
|
||||||
|
public boolean isDebug(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be a base64 string 8 bytes in length.
|
||||||
|
*/
|
||||||
public String getUUID(){
|
public String getUUID(){
|
||||||
String uuid = Settings.getString("uuid", "");
|
String uuid = Settings.getString("uuid", "");
|
||||||
if(uuid.isEmpty()){
|
if(uuid.isEmpty()){
|
||||||
@@ -62,12 +119,21 @@ public abstract class Platform {
|
|||||||
}
|
}
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
/**Only used for iOS or android: open the share menu for a map or save.*/
|
|
||||||
public void shareFile(FileHandle file){}
|
|
||||||
/**Download a file. Only used on GWT backend.*/
|
|
||||||
public void downloadFile(String name, byte[] bytes){}
|
|
||||||
|
|
||||||
/**Show a file chooser. Desktop only.
|
/**
|
||||||
|
* Only used for iOS or android: open the share menu for a map or save.
|
||||||
|
*/
|
||||||
|
public void shareFile(FileHandle file){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download a file. Only used on GWT backend.
|
||||||
|
*/
|
||||||
|
public void downloadFile(String name, byte[] bytes){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a file chooser. Desktop only.
|
||||||
*
|
*
|
||||||
* @param text File chooser title text
|
* @param text File chooser title text
|
||||||
* @param content Description of the type of files to be loaded
|
* @param content Description of the type of files to be loaded
|
||||||
@@ -75,24 +141,54 @@ public abstract class Platform {
|
|||||||
* @param open Whether to open or save files
|
* @param open Whether to open or save files
|
||||||
* @param filetype File extension to filter
|
* @param filetype File extension to filter
|
||||||
*/
|
*/
|
||||||
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, String filetype){}
|
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, String filetype){
|
||||||
/**Use the default thread provider from the kryonet module for this.*/
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the default thread provider from the kryonet module for this.
|
||||||
|
*/
|
||||||
public ThreadProvider getThreadProvider(){
|
public ThreadProvider getThreadProvider(){
|
||||||
return new ThreadProvider(){
|
return new ThreadProvider(){
|
||||||
@Override public boolean isOnThread() {return true;}
|
@Override
|
||||||
@Override public void sleep(long ms) {}
|
public boolean isOnThread(){
|
||||||
@Override public void start(Runnable run) {}
|
return true;
|
||||||
@Override public void stop() {}
|
}
|
||||||
@Override public void notify(Object object) {}
|
|
||||||
@Override public void wait(Object object) {}
|
@Override
|
||||||
|
public void sleep(long ms){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void start(Runnable run){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop(){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notify(Object object){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void wait(Object object){
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO iOS implementation
|
//TODO iOS implementation
|
||||||
/**Forces the app into landscape mode. Currently Android only.*/
|
|
||||||
public void beginForceLandscape(){}
|
/**
|
||||||
|
* Forces the app into landscape mode. Currently Android only.
|
||||||
|
*/
|
||||||
|
public void beginForceLandscape(){
|
||||||
|
}
|
||||||
|
|
||||||
//TODO iOS implementation
|
//TODO iOS implementation
|
||||||
/**Stops forcing the app into landscape orientation. Currently Android only.*/
|
|
||||||
public void endForceLandscape(){}
|
/**
|
||||||
|
* Stops forcing the app into landscape orientation. Currently Android only.
|
||||||
|
*/
|
||||||
|
public void endForceLandscape(){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,13 +12,12 @@ import static io.anuke.mindustry.Vars.logic;
|
|||||||
public class ThreadHandler{
|
public class ThreadHandler{
|
||||||
private final Queue<Runnable> toRun = new Queue<>();
|
private final Queue<Runnable> toRun = new Queue<>();
|
||||||
private final ThreadProvider impl;
|
private final ThreadProvider impl;
|
||||||
|
private final Object updateLock = new Object();
|
||||||
private float delta = 1f;
|
private float delta = 1f;
|
||||||
private float smoothDelta = 1f;
|
private float smoothDelta = 1f;
|
||||||
private long frame = 0, lastDeltaUpdate;
|
private long frame = 0, lastDeltaUpdate;
|
||||||
private float framesSinceUpdate;
|
private float framesSinceUpdate;
|
||||||
private boolean enabled;
|
private boolean enabled;
|
||||||
|
|
||||||
private final Object updateLock = new Object();
|
|
||||||
private boolean rendered = true;
|
private boolean rendered = true;
|
||||||
|
|
||||||
public ThreadHandler(ThreadProvider impl){
|
public ThreadHandler(ThreadProvider impl){
|
||||||
@@ -82,6 +81,10 @@ public class ThreadHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEnabled(){
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
public void setEnabled(boolean enabled){
|
public void setEnabled(boolean enabled){
|
||||||
if(enabled){
|
if(enabled){
|
||||||
logic.doUpdate = false;
|
logic.doUpdate = false;
|
||||||
@@ -98,10 +101,6 @@ public class ThreadHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabled(){
|
|
||||||
return enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean doInterpolate(){
|
public boolean doInterpolate(){
|
||||||
return enabled && Gdx.graphics.getFramesPerSecond() - getTPS() > 20 && getTPS() < 30;
|
return enabled && Gdx.graphics.getFramesPerSecond() - getTPS() > 20 && getTPS() < 30;
|
||||||
}
|
}
|
||||||
@@ -166,10 +165,15 @@ public class ThreadHandler {
|
|||||||
|
|
||||||
public interface ThreadProvider{
|
public interface ThreadProvider{
|
||||||
boolean isOnThread();
|
boolean isOnThread();
|
||||||
|
|
||||||
void sleep(long ms) throws InterruptedException;
|
void sleep(long ms) throws InterruptedException;
|
||||||
|
|
||||||
void start(Runnable run);
|
void start(Runnable run);
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void wait(Object object) throws InterruptedException;
|
void wait(Object object) throws InterruptedException;
|
||||||
|
|
||||||
void notify(Object object);
|
void notify(Object object);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,14 @@ import static io.anuke.mindustry.Vars.players;
|
|||||||
import static io.anuke.ucore.scene.actions.Actions.*;
|
import static io.anuke.ucore.scene.actions.Actions.*;
|
||||||
|
|
||||||
public class UI extends SceneModule{
|
public class UI extends SceneModule{
|
||||||
|
public final MenuFragment menufrag = new MenuFragment();
|
||||||
|
public final HudFragment hudfrag = new HudFragment();
|
||||||
|
public final ChatFragment chatfrag = new ChatFragment();
|
||||||
|
public final PlayerListFragment listfrag = new PlayerListFragment();
|
||||||
|
public final BackgroundFragment backfrag = new BackgroundFragment();
|
||||||
|
public final LoadingFragment loadfrag = new LoadingFragment();
|
||||||
|
public final DebugFragment debugfrag = new DebugFragment();
|
||||||
|
|
||||||
public AboutDialog about;
|
public AboutDialog about;
|
||||||
public RestartDialog restart;
|
public RestartDialog restart;
|
||||||
public LevelDialog levels;
|
public LevelDialog levels;
|
||||||
@@ -59,14 +67,6 @@ public class UI extends SceneModule{
|
|||||||
public UnlocksDialog unlocks;
|
public UnlocksDialog unlocks;
|
||||||
public ContentInfoDialog content;
|
public ContentInfoDialog content;
|
||||||
|
|
||||||
public final MenuFragment menufrag = new MenuFragment();
|
|
||||||
public final HudFragment hudfrag = new HudFragment();
|
|
||||||
public final ChatFragment chatfrag = new ChatFragment();
|
|
||||||
public final PlayerListFragment listfrag = new PlayerListFragment();
|
|
||||||
public final BackgroundFragment backfrag = new BackgroundFragment();
|
|
||||||
public final LoadingFragment loadfrag = new LoadingFragment();
|
|
||||||
public final DebugFragment debugfrag = new DebugFragment();
|
|
||||||
|
|
||||||
private Locale lastLocale;
|
private Locale lastLocale;
|
||||||
|
|
||||||
public UI(){
|
public UI(){
|
||||||
@@ -234,7 +234,8 @@ public class UI extends SceneModule{
|
|||||||
public void showTextInput(String title, String text, String def, TextFieldFilter filter, Consumer<String> confirmed){
|
public void showTextInput(String title, String text, String def, TextFieldFilter filter, Consumer<String> confirmed){
|
||||||
new Dialog(title, "dialog"){{
|
new Dialog(title, "dialog"){{
|
||||||
content().margin(30).add(text).padRight(6f);
|
content().margin(30).add(text).padRight(6f);
|
||||||
TextField field = content().addField(def, t->{}).size(170f, 50f).get();
|
TextField field = content().addField(def, t -> {
|
||||||
|
}).size(170f, 50f).get();
|
||||||
field.setTextFieldFilter((f, c) -> field.getText().length() < 12 && filter.acceptChar(f, c));
|
field.setTextFieldFilter((f, c) -> field.getText().length() < 12 && filter.acceptChar(f, c));
|
||||||
Platform.instance.addDialog(field);
|
Platform.instance.addDialog(field);
|
||||||
buttons().defaults().size(120, 54).pad(4);
|
buttons().defaults().size(120, 54).pad(4);
|
||||||
@@ -286,20 +287,4 @@ public class UI extends SceneModule{
|
|||||||
dialog.keyDown(Keys.BACK, dialog::hide);
|
dialog.keyDown(Keys.BACK, dialog::hide);
|
||||||
dialog.show();
|
dialog.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showConfirmListen(String title, String text, Consumer<Boolean> listener){
|
|
||||||
FloatingDialog dialog = new FloatingDialog(title);
|
|
||||||
dialog.content().add(text).pad(4f);
|
|
||||||
dialog.buttons().defaults().size(200f, 54f).pad(2f);
|
|
||||||
dialog.buttons().addButton("$text.cancel", () -> {
|
|
||||||
dialog.hide();
|
|
||||||
listener.accept(true);
|
|
||||||
});
|
|
||||||
dialog.buttons().addButton("$text.ok", () -> {
|
|
||||||
dialog.hide();
|
|
||||||
listener.accept(true);
|
|
||||||
});
|
|
||||||
dialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ import io.anuke.mindustry.core.GameState.State;
|
|||||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.mindustry.io.*;
|
import io.anuke.mindustry.io.Map;
|
||||||
|
import io.anuke.mindustry.io.MapIO;
|
||||||
|
import io.anuke.mindustry.io.MapMeta;
|
||||||
|
import io.anuke.mindustry.io.Maps;
|
||||||
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.mapgen.WorldGenerator;
|
import io.anuke.mindustry.world.mapgen.WorldGenerator;
|
||||||
@@ -93,6 +96,10 @@ public class World extends Module{
|
|||||||
return currentMap;
|
return currentMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMap(Map map){
|
||||||
|
this.currentMap = map;
|
||||||
|
}
|
||||||
|
|
||||||
public int width(){
|
public int width(){
|
||||||
return tiles == null ? 0 : tiles.length;
|
return tiles == null ? 0 : tiles.length;
|
||||||
}
|
}
|
||||||
@@ -143,8 +150,10 @@ public class World extends Module{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Resizes the tile array to the specified size and returns the resulting tile array.
|
/**
|
||||||
* Only use for loading saves!*/
|
* Resizes the tile array to the specified size and returns the resulting tile array.
|
||||||
|
* Only use for loading saves!
|
||||||
|
*/
|
||||||
public Tile[][] createTiles(int width, int height){
|
public Tile[][] createTiles(int width, int height){
|
||||||
if(tiles != null){
|
if(tiles != null){
|
||||||
clearTileEntities();
|
clearTileEntities();
|
||||||
@@ -159,14 +168,18 @@ public class World extends Module{
|
|||||||
return tiles;
|
return tiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Call to signify the beginning of map loading.
|
/**
|
||||||
* TileChangeEvents will not be fired until endMapLoad().*/
|
* Call to signify the beginning of map loading.
|
||||||
|
* TileChangeEvents will not be fired until endMapLoad().
|
||||||
|
*/
|
||||||
public void beginMapLoad(){
|
public void beginMapLoad(){
|
||||||
generating = true;
|
generating = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Call to signify the end of map loading. Updates tile occlusions and sets up physics for the world.
|
/**
|
||||||
* A WorldLoadEvent will be fire.*/
|
* Call to signify the end of map loading. Updates tile occlusions and sets up physics for the world.
|
||||||
|
* A WorldLoadEvent will be fire.
|
||||||
|
*/
|
||||||
public void endMapLoad(){
|
public void endMapLoad(){
|
||||||
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++){
|
||||||
@@ -184,7 +197,9 @@ public class World extends Module{
|
|||||||
Events.fire(WorldLoadEvent.class);
|
Events.fire(WorldLoadEvent.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Loads up a procedural map. This does not call play(), but calls reset().*/
|
/**
|
||||||
|
* Loads up a procedural map. This does not call play(), but calls reset().
|
||||||
|
*/
|
||||||
public void loadProceduralMap(){
|
public void loadProceduralMap(){
|
||||||
Timers.mark();
|
Timers.mark();
|
||||||
Timers.mark();
|
Timers.mark();
|
||||||
@@ -213,10 +228,6 @@ public class World extends Module{
|
|||||||
Log.info("Full time to generate: {0}", Timers.elapsed());
|
Log.info("Full time to generate: {0}", Timers.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMap(Map map){
|
|
||||||
this.currentMap = map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadMap(Map map){
|
public void loadMap(Map map){
|
||||||
loadMap(map, MathUtils.random(0, 999999));
|
loadMap(map, MathUtils.random(0, 999999));
|
||||||
}
|
}
|
||||||
@@ -290,14 +301,19 @@ public class World extends Module{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Raycast, but with world coordinates.*/
|
/**
|
||||||
|
* Raycast, but with world coordinates.
|
||||||
|
*/
|
||||||
public GridPoint2 raycastWorld(float x, float y, float x2, float y2){
|
public GridPoint2 raycastWorld(float x, float y, float x2, float y2){
|
||||||
return raycast(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize),
|
return raycast(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize),
|
||||||
Mathf.scl2(x2, tilesize), Mathf.scl2(y2, tilesize));
|
Mathf.scl2(x2, tilesize), Mathf.scl2(y2, tilesize));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Input is in block coordinates, not world coordinates.
|
/**
|
||||||
* @return null if no collisions found, block position otherwise.*/
|
* Input is in block coordinates, not world coordinates.
|
||||||
|
*
|
||||||
|
* @return null if no collisions found, block position otherwise.
|
||||||
|
*/
|
||||||
public GridPoint2 raycast(int x0f, int y0f, int x1, int y1){
|
public GridPoint2 raycast(int x0f, int y0f, int x1, int y1){
|
||||||
int x0 = x0f;
|
int x0 = x0f;
|
||||||
int y0 = y0f;
|
int y0 = y0f;
|
||||||
|
|||||||
@@ -7,11 +7,17 @@ import io.anuke.mindustry.io.MapTileData.TileDataMarker;
|
|||||||
import io.anuke.ucore.util.Bits;
|
import io.anuke.ucore.util.Bits;
|
||||||
|
|
||||||
public class DrawOperation{
|
public class DrawOperation{
|
||||||
/**Data to apply operation to.*/
|
/**
|
||||||
|
* Data to apply operation to.
|
||||||
|
*/
|
||||||
private MapTileData data;
|
private MapTileData data;
|
||||||
/**List of per-tile operations that occurred.*/
|
/**
|
||||||
|
* List of per-tile operations that occurred.
|
||||||
|
*/
|
||||||
private Array<TileOperation> operations = new Array<>();
|
private Array<TileOperation> operations = new Array<>();
|
||||||
/**Checks for duplicate operations, useful for brushes.*/
|
/**
|
||||||
|
* Checks for duplicate operations, useful for brushes.
|
||||||
|
*/
|
||||||
private IntSet checks = new IntSet();
|
private IntSet checks = new IntSet();
|
||||||
|
|
||||||
public DrawOperation(MapTileData data){
|
public DrawOperation(MapTileData data){
|
||||||
|
|||||||
@@ -56,14 +56,14 @@ public class MapEditor{
|
|||||||
renderer.resize(map.width(), map.height());
|
renderer.resize(map.width(), map.height());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDrawElevation(int elevation){
|
|
||||||
this.elevation = (byte)elevation;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte getDrawElevation(){
|
public byte getDrawElevation(){
|
||||||
return elevation;
|
return elevation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDrawElevation(int elevation){
|
||||||
|
this.elevation = (byte) elevation;
|
||||||
|
}
|
||||||
|
|
||||||
public int getDrawRotation(){
|
public int getDrawRotation(){
|
||||||
return rotation;
|
return rotation;
|
||||||
}
|
}
|
||||||
@@ -72,14 +72,14 @@ public class MapEditor{
|
|||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setDrawTeam(Team team){
|
|
||||||
this.drawTeam = team;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Team getDrawTeam(){
|
public Team getDrawTeam(){
|
||||||
return drawTeam;
|
return drawTeam;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setDrawTeam(Team team){
|
||||||
|
this.drawTeam = team;
|
||||||
|
}
|
||||||
|
|
||||||
public Block getDrawBlock(){
|
public Block getDrawBlock(){
|
||||||
return drawBlock;
|
return drawBlock;
|
||||||
}
|
}
|
||||||
@@ -88,14 +88,14 @@ public class MapEditor{
|
|||||||
this.drawBlock = block;
|
this.drawBlock = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBrushSize(int size){
|
|
||||||
this.brushSize = size;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBrushSize(){
|
public int getBrushSize(){
|
||||||
return brushSize;
|
return brushSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setBrushSize(int size){
|
||||||
|
this.brushSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
public void draw(int x, int y){
|
public void draw(int x, int y){
|
||||||
draw(x, y, drawBlock);
|
draw(x, y, drawBlock);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -284,11 +284,13 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
saved = true;
|
saved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Argument format:
|
/**
|
||||||
|
* Argument format:
|
||||||
* 0) button name
|
* 0) button name
|
||||||
* 1) description
|
* 1) description
|
||||||
* 2) icon name
|
* 2) icon name
|
||||||
* 3) listener */
|
* 3) listener
|
||||||
|
*/
|
||||||
private FloatingDialog createDialog(String title, Object... arguments){
|
private FloatingDialog createDialog(String title, Object... arguments){
|
||||||
FloatingDialog dialog = new FloatingDialog(title);
|
FloatingDialog dialog = new FloatingDialog(title);
|
||||||
|
|
||||||
@@ -584,7 +586,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
|||||||
|
|
||||||
for(Block block : Block.all()){
|
for(Block block : Block.all()){
|
||||||
TextureRegion[] regions = block.getCompactIcon();
|
TextureRegion[] regions = block.getCompactIcon();
|
||||||
if((block.synthetic() && (Recipe.getByResult(block) == null || !control.database().isUnlocked(Recipe.getByResult(block)))) && !debug && block != StorageBlocks.core) continue;
|
if((block.synthetic() && (Recipe.getByResult(block) == null || !control.database().isUnlocked(Recipe.getByResult(block)))) && !debug && block != StorageBlocks.core)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(regions.length == 0 || regions[0] == Draw.region("jjfgj")) continue;
|
if(regions.length == 0 || regions[0] == Draw.region("jjfgj")) continue;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package io.anuke.mindustry.editor;
|
package io.anuke.mindustry.editor;
|
||||||
|
|
||||||
import io.anuke.mindustry.io.Map;
|
|
||||||
import io.anuke.mindustry.core.Platform;
|
import io.anuke.mindustry.core.Platform;
|
||||||
|
import io.anuke.mindustry.io.Map;
|
||||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||||
import io.anuke.ucore.function.Consumer;
|
import io.anuke.ucore.function.Consumer;
|
||||||
import io.anuke.ucore.scene.ui.TextButton;
|
import io.anuke.ucore.scene.ui.TextButton;
|
||||||
|
|||||||
@@ -53,51 +53,6 @@ public class MapView extends Element implements GestureListener{
|
|||||||
private float mousex, mousey;
|
private float mousex, mousey;
|
||||||
private EditorTool lastTool;
|
private EditorTool lastTool;
|
||||||
|
|
||||||
public void setTool(EditorTool tool){
|
|
||||||
this.tool = tool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public EditorTool getTool() {
|
|
||||||
return tool;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearStack(){
|
|
||||||
stack.clear();
|
|
||||||
//TODO clear und obuffer
|
|
||||||
}
|
|
||||||
|
|
||||||
public OperationStack getStack() {
|
|
||||||
return stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGrid(boolean grid) {
|
|
||||||
this.grid = grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isGrid() {
|
|
||||||
return grid;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void undo(){
|
|
||||||
if(stack.canUndo()){
|
|
||||||
stack.undo(editor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void redo(){
|
|
||||||
if(stack.canRedo()){
|
|
||||||
stack.redo(editor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addTileOp(TileOperation t){
|
|
||||||
op.addOperation(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkForDuplicates(short x, short y){
|
|
||||||
return op.checkDuplicate(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapView(MapEditor editor){
|
public MapView(MapEditor editor){
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
|
|
||||||
@@ -211,6 +166,51 @@ public class MapView extends Element implements GestureListener{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EditorTool getTool(){
|
||||||
|
return tool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTool(EditorTool tool){
|
||||||
|
this.tool = tool;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearStack(){
|
||||||
|
stack.clear();
|
||||||
|
//TODO clear und obuffer
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationStack getStack(){
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGrid(){
|
||||||
|
return grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGrid(boolean grid){
|
||||||
|
this.grid = grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void undo(){
|
||||||
|
if(stack.canUndo()){
|
||||||
|
stack.undo(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void redo(){
|
||||||
|
if(stack.canRedo()){
|
||||||
|
stack.redo(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addTileOp(TileOperation t){
|
||||||
|
op.addOperation(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkForDuplicates(short x, short y){
|
||||||
|
return op.checkDuplicate(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void act(float delta){
|
public void act(float delta){
|
||||||
super.act(delta);
|
super.act(delta);
|
||||||
|
|||||||
@@ -24,13 +24,17 @@ import io.anuke.ucore.util.Translator;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
/**Utility class for damaging in an area.*/
|
/**
|
||||||
|
* Utility class for damaging in an area.
|
||||||
|
*/
|
||||||
public class Damage{
|
public class Damage{
|
||||||
private static Rectangle rect = new Rectangle();
|
private static Rectangle rect = new Rectangle();
|
||||||
private static Rectangle hitrect = new Rectangle();
|
private static Rectangle hitrect = new Rectangle();
|
||||||
private static Translator tr = new Translator();
|
private static Translator tr = new Translator();
|
||||||
|
|
||||||
/**Creates a dynamic explosion based on specified parameters.*/
|
/**
|
||||||
|
* Creates a dynamic explosion based on specified parameters.
|
||||||
|
*/
|
||||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){
|
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){
|
||||||
for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){
|
for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){
|
||||||
int branches = 5 + Mathf.clamp((int) (power / 30), 1, 20);
|
int branches = 5 + Mathf.clamp((int) (power / 30), 1, 20);
|
||||||
@@ -76,8 +80,10 @@ public class Damage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Damages entities in a line.
|
/**
|
||||||
* Only enemies of the specified team are damaged.*/
|
* Damages entities in a line.
|
||||||
|
* Only enemies of the specified team are damaged.
|
||||||
|
*/
|
||||||
public static void collideLine(SolidEntity hitter, Team team, Effect effect, float x, float y, float angle, float length){
|
public static void collideLine(SolidEntity hitter, Team team, Effect effect, float x, float y, float angle, float length){
|
||||||
tr.trns(angle, length);
|
tr.trns(angle, length);
|
||||||
rect.setPosition(x, y).setSize(tr.x, tr.y);
|
rect.setPosition(x, y).setSize(tr.x, tr.y);
|
||||||
@@ -120,7 +126,9 @@ public class Damage {
|
|||||||
Units.getNearbyEnemies(team, rect, cons);
|
Units.getNearbyEnemies(team, rect, cons);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Damages all entities and blocks in a radius that are enemies of the team.*/
|
/**
|
||||||
|
* Damages all entities and blocks in a radius that are enemies of the team.
|
||||||
|
*/
|
||||||
public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate<Unit> predicate, Consumer<Unit> acceptor){
|
public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate<Unit> predicate, Consumer<Unit> acceptor){
|
||||||
Consumer<Unit> cons = entity -> {
|
Consumer<Unit> cons = entity -> {
|
||||||
if(!predicate.test(entity)) return;
|
if(!predicate.test(entity)) return;
|
||||||
@@ -141,12 +149,16 @@ public class Damage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Damages everything in a radius.*/
|
/**
|
||||||
|
* Damages everything in a radius.
|
||||||
|
*/
|
||||||
public static void damage(float x, float y, float radius, float damage){
|
public static void damage(float x, float y, float radius, float damage){
|
||||||
damage(null, x, y, radius, damage);
|
damage(null, x, y, radius, damage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Damages all entities and blocks in a radius that are enemies of the team.*/
|
/**
|
||||||
|
* Damages all entities and blocks in a radius that are enemies of the team.
|
||||||
|
*/
|
||||||
public static void damage(Team team, float x, float y, float radius, float damage){
|
public static void damage(Team team, float x, float y, float radius, float damage){
|
||||||
Consumer<Unit> cons = entity -> {
|
Consumer<Unit> cons = entity -> {
|
||||||
if(entity.team == team || entity.distanceTo(x, y) > radius){
|
if(entity.team == team || entity.distanceTo(x, y) > radius){
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ import io.anuke.mindustry.world.Tile;
|
|||||||
import io.anuke.mindustry.world.blocks.Floor;
|
import io.anuke.mindustry.world.blocks.Floor;
|
||||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock.CoreEntity;
|
import io.anuke.mindustry.world.blocks.storage.CoreBlock.CoreEntity;
|
||||||
import io.anuke.mindustry.world.blocks.units.MechFactory;
|
import io.anuke.mindustry.world.blocks.units.MechFactory;
|
||||||
import io.anuke.ucore.core.*;
|
import io.anuke.ucore.core.Core;
|
||||||
|
import io.anuke.ucore.core.Graphics;
|
||||||
|
import io.anuke.ucore.core.Inputs;
|
||||||
|
import io.anuke.ucore.core.Timers;
|
||||||
import io.anuke.ucore.entities.EntityGroup;
|
import io.anuke.ucore.entities.EntityGroup;
|
||||||
import io.anuke.ucore.entities.trait.SolidTrait;
|
import io.anuke.ucore.entities.trait.SolidTrait;
|
||||||
import io.anuke.ucore.graphics.Draw;
|
import io.anuke.ucore.graphics.Draw;
|
||||||
@@ -40,13 +43,11 @@ import java.io.IOException;
|
|||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTrait{
|
public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTrait{
|
||||||
|
public static final int timerSync = 2;
|
||||||
private static final int timerShootLeft = 0;
|
private static final int timerShootLeft = 0;
|
||||||
private static final int timerShootRight = 1;
|
private static final int timerShootRight = 1;
|
||||||
|
|
||||||
public static final int timerSync = 2;
|
|
||||||
|
|
||||||
//region instance variables, constructor
|
//region instance variables, constructor
|
||||||
|
|
||||||
public float baseRotation;
|
public float baseRotation;
|
||||||
|
|
||||||
public float pointerX, pointerY;
|
public float pointerX, pointerY;
|
||||||
@@ -82,6 +83,30 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
|||||||
|
|
||||||
//region unit and event overrides, utility methods
|
//region unit and event overrides, utility methods
|
||||||
|
|
||||||
|
@Remote(in = In.entities, targets = Loc.server, called = Loc.server)
|
||||||
|
public static void onPlayerDamage(Player player, float amount){
|
||||||
|
if(player == null) return;
|
||||||
|
|
||||||
|
player.hitTime = hitDuration;
|
||||||
|
player.health -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(in = In.entities, targets = Loc.server, called = Loc.server)
|
||||||
|
public static void onPlayerDeath(Player player){
|
||||||
|
if(player == null) return;
|
||||||
|
|
||||||
|
player.dead = true;
|
||||||
|
player.placeQueue.clear();
|
||||||
|
|
||||||
|
player.dropCarry();
|
||||||
|
|
||||||
|
float explosiveness = 2f + (player.inventory.hasItem() ? player.inventory.getItem().item.explosiveness * player.inventory.getItem().amount : 0f);
|
||||||
|
float flammability = (player.inventory.hasItem() ? player.inventory.getItem().item.flammability * player.inventory.getItem().amount : 0f);
|
||||||
|
Damage.dynamicExplosion(player.x, player.y, flammability, explosiveness, 0f, player.getSize() / 2f, Palette.darkFlame);
|
||||||
|
|
||||||
|
ScorchDecal.create(player.x, player.y);
|
||||||
|
player.onDeath();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Timer getTimer(){
|
public Timer getTimer(){
|
||||||
@@ -215,31 +240,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
|||||||
return super.collides(other) || other instanceof ItemDrop;
|
return super.collides(other) || other instanceof ItemDrop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(in = In.entities, targets = Loc.server, called = Loc.server)
|
|
||||||
public static void onPlayerDamage(Player player, float amount){
|
|
||||||
if(player == null) return;
|
|
||||||
|
|
||||||
player.hitTime = hitDuration;
|
|
||||||
player.health -= amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(in = In.entities, targets = Loc.server, called = Loc.server)
|
|
||||||
public static void onPlayerDeath(Player player){
|
|
||||||
if(player == null) return;
|
|
||||||
|
|
||||||
player.dead = true;
|
|
||||||
player.placeQueue.clear();
|
|
||||||
|
|
||||||
player.dropCarry();
|
|
||||||
|
|
||||||
float explosiveness = 2f + (player.inventory.hasItem() ? player.inventory.getItem().item.explosiveness * player.inventory.getItem().amount : 0f);
|
|
||||||
float flammability = (player.inventory.hasItem() ? player.inventory.getItem().item.flammability * player.inventory.getItem().amount : 0f);
|
|
||||||
Damage.dynamicExplosion(player.x, player.y, flammability, explosiveness, 0f, player.getSize()/2f, Palette.darkFlame);
|
|
||||||
|
|
||||||
ScorchDecal.create(player.x, player.y);
|
|
||||||
player.onDeath();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void set(float x, float y){
|
public void set(float x, float y){
|
||||||
this.x = x;
|
this.x = x;
|
||||||
@@ -402,7 +402,9 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
|||||||
Draw.tscl(fontScale);
|
Draw.tscl(fontScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Draw all current build requests. Does not draw the beam effect, only the positions.*/
|
/**
|
||||||
|
* Draw all current build requests. Does not draw the beam effect, only the positions.
|
||||||
|
*/
|
||||||
public void drawBuildRequests(){
|
public void drawBuildRequests(){
|
||||||
synchronized(getPlaceQueue()){
|
synchronized(getPlaceQueue()){
|
||||||
for(BuildRequest request : getPlaceQueue()){
|
for(BuildRequest request : getPlaceQueue()){
|
||||||
@@ -661,7 +663,9 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
|||||||
team = (team == Team.blue ? Team.red : Team.blue);
|
team = (team == Team.blue ? Team.red : Team.blue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Resets all values of the player.*/
|
/**
|
||||||
|
* Resets all values of the player.
|
||||||
|
*/
|
||||||
public void reset(){
|
public void reset(){
|
||||||
status.clear();
|
status.clear();
|
||||||
team = Team.blue;
|
team = Team.blue;
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ import com.badlogic.gdx.math.Vector2;
|
|||||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
|
||||||
/**Class for predicting shoot angles based on velocities of targets.*/
|
/**
|
||||||
|
* Class for predicting shoot angles based on velocities of targets.
|
||||||
|
*/
|
||||||
public class Predict{
|
public class Predict{
|
||||||
private static Vector2 vec = new Vector2();
|
private static Vector2 vec = new Vector2();
|
||||||
private static Vector2 vresult = new Vector2();
|
private static Vector2 vresult = new Vector2();
|
||||||
|
|
||||||
/**Calculates of intercept of a stationary and moving target. Do not call from multiple threads!
|
/**
|
||||||
|
* Calculates of intercept of a stationary and moving target. Do not call from multiple threads!
|
||||||
|
*
|
||||||
* @param srcx X of shooter
|
* @param srcx X of shooter
|
||||||
* @param srcy Y of shooter
|
* @param srcy Y of shooter
|
||||||
* @param dstx X of target
|
* @param dstx X of target
|
||||||
@@ -17,7 +21,8 @@ public class Predict {
|
|||||||
* @param dstvx X velocity of target (subtract shooter X velocity if needed)
|
* @param dstvx X velocity of target (subtract shooter X velocity if needed)
|
||||||
* @param dstvy Y velocity of target (subtract shooter Y velocity if needed)
|
* @param dstvy Y velocity of target (subtract shooter Y velocity if needed)
|
||||||
* @param v speed of bullet
|
* @param v speed of bullet
|
||||||
* @return the intercept location*/
|
* @return the intercept location
|
||||||
|
*/
|
||||||
public static Vector2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v){
|
public static Vector2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v){
|
||||||
float tx = dstx - srcx,
|
float tx = dstx - srcx,
|
||||||
ty = dsty - srcy;
|
ty = dsty - srcy;
|
||||||
@@ -44,7 +49,9 @@ public class Predict {
|
|||||||
return sol;
|
return sol;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**See {@link #intercept(float, float, float, float, float, float, float)}.*/
|
/**
|
||||||
|
* See {@link #intercept(float, float, float, float, float, float, float)}.
|
||||||
|
*/
|
||||||
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){
|
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){
|
||||||
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getVelocity().x - src.getVelocity().x, dst.getVelocity().x - src.getVelocity().y, v);
|
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getVelocity().x - src.getVelocity().x, dst.getVelocity().x - src.getVelocity().y, v);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ import java.io.DataInput;
|
|||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**Class for controlling status effects on an entity.*/
|
/**
|
||||||
|
* Class for controlling status effects on an entity.
|
||||||
|
*/
|
||||||
public class StatusController implements Saveable{
|
public class StatusController implements Saveable{
|
||||||
private static final StatusEntry globalResult = new StatusEntry();
|
private static final StatusEntry globalResult = new StatusEntry();
|
||||||
private static final Array<StatusEntry> removals = new ThreadArray<>();
|
private static final Array<StatusEntry> removals = new ThreadArray<>();
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ import static io.anuke.mindustry.Vars.world;
|
|||||||
|
|
||||||
public class TileEntity extends BaseEntity implements TargetTrait{
|
public class TileEntity extends BaseEntity implements TargetTrait{
|
||||||
public static final float timeToSleep = 60f * 4; //4 seconds to fall asleep
|
public static final float timeToSleep = 60f * 4; //4 seconds to fall asleep
|
||||||
/**This value is only used for debugging.*/
|
|
||||||
public static int sleepingEntities = 0;
|
|
||||||
|
|
||||||
private static final ObjectSet<Tile> tmpTiles = new ObjectSet<>();
|
private static final ObjectSet<Tile> tmpTiles = new ObjectSet<>();
|
||||||
|
/**
|
||||||
|
* This value is only used for debugging.
|
||||||
|
*/
|
||||||
|
public static int sleepingEntities = 0;
|
||||||
public Tile tile;
|
public Tile tile;
|
||||||
public Timer timer;
|
public Timer timer;
|
||||||
public float health;
|
public float health;
|
||||||
@@ -51,13 +51,25 @@ public class TileEntity extends BaseEntity implements TargetTrait {
|
|||||||
public LiquidModule liquids;
|
public LiquidModule liquids;
|
||||||
public ConsumeModule cons;
|
public ConsumeModule cons;
|
||||||
|
|
||||||
//list of (cached) tiles with entities in proximity, used for outputting to
|
/**List of (cached) tiles with entities in proximity, used for outputting to*/
|
||||||
//TODO implement
|
|
||||||
private Array<Tile> proximity = new Array<>(8);
|
private Array<Tile> proximity = new Array<>(8);
|
||||||
private boolean dead = false;
|
private boolean dead = false;
|
||||||
private boolean sleeping;
|
private boolean sleeping;
|
||||||
private float sleepTime;
|
private float sleepTime;
|
||||||
|
|
||||||
|
@Remote(called = Loc.server, in = In.blocks)
|
||||||
|
public static void onTileDamage(Tile tile, float health){
|
||||||
|
if(tile.entity != null){
|
||||||
|
tile.entity.health = health;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(called = Loc.server, in = In.blocks)
|
||||||
|
public static void onTileDestroyed(Tile tile){
|
||||||
|
if(tile.entity == null) return;
|
||||||
|
tile.entity.onDeath();
|
||||||
|
}
|
||||||
|
|
||||||
/**Sets this tile entity data to this tile, and adds it if necessary.*/
|
/**Sets this tile entity data to this tile, and adds it if necessary.*/
|
||||||
public TileEntity init(Tile tile, boolean added){
|
public TileEntity init(Tile tile, boolean added){
|
||||||
this.tile = tile;
|
this.tile = tile;
|
||||||
@@ -75,8 +87,10 @@ public class TileEntity extends BaseEntity implements TargetTrait {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Call when nothing is happening to the entity.
|
/**
|
||||||
* This increments the internal sleep timer.*/
|
* Call when nothing is happening to the entity.
|
||||||
|
* This increments the internal sleep timer.
|
||||||
|
*/
|
||||||
public void sleep(){
|
public void sleep(){
|
||||||
sleepTime += Timers.delta();
|
sleepTime += Timers.delta();
|
||||||
if(!sleeping && sleepTime >= timeToSleep){
|
if(!sleeping && sleepTime >= timeToSleep){
|
||||||
@@ -86,8 +100,10 @@ public class TileEntity extends BaseEntity implements TargetTrait {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Call when something just happened to the entity.
|
/**
|
||||||
* If the entity was sleeping, this enables it. This also resets the sleep timer.*/
|
* Call when something just happened to the entity.
|
||||||
|
* If the entity was sleeping, this enables it. This also resets the sleep timer.
|
||||||
|
*/
|
||||||
public void wakeUp(){
|
public void wakeUp(){
|
||||||
sleepTime = 0f;
|
sleepTime = 0f;
|
||||||
if(sleeping){
|
if(sleeping){
|
||||||
@@ -105,8 +121,11 @@ public class TileEntity extends BaseEntity implements TargetTrait {
|
|||||||
return dead;
|
return dead;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void write(DataOutputStream stream) throws IOException{}
|
public void write(DataOutputStream stream) throws IOException{
|
||||||
public void read(DataInputStream stream) throws IOException{}
|
}
|
||||||
|
|
||||||
|
public void read(DataInputStream stream) throws IOException{
|
||||||
|
}
|
||||||
|
|
||||||
private void onDeath(){
|
private void onDeath(){
|
||||||
if(!dead){
|
if(!dead){
|
||||||
@@ -231,17 +250,4 @@ public class TileEntity extends BaseEntity implements TargetTrait {
|
|||||||
public EntityGroup targetGroup(){
|
public EntityGroup targetGroup(){
|
||||||
return tileGroup;
|
return tileGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(called = Loc.server, in = In.blocks)
|
|
||||||
public static void onTileDamage(Tile tile, float health){
|
|
||||||
if(tile.entity != null){
|
|
||||||
tile.entity.health = health;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(called = Loc.server, in = In.blocks)
|
|
||||||
public static void onTileDestroyed(Tile tile){
|
|
||||||
if(tile.entity == null) return;
|
|
||||||
tile.entity.onDeath();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,11 +32,17 @@ import static io.anuke.mindustry.Vars.state;
|
|||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait, InventoryTrait{
|
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait, InventoryTrait{
|
||||||
/**total duration of hit flash effect*/
|
/**
|
||||||
|
* total duration of hit flash effect
|
||||||
|
*/
|
||||||
public static final float hitDuration = 9f;
|
public static final float hitDuration = 9f;
|
||||||
/**Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks.*/
|
/**
|
||||||
|
* Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks.
|
||||||
|
*/
|
||||||
public static final float velocityPercision = 8f;
|
public static final float velocityPercision = 8f;
|
||||||
/**Maximum absolute value of a velocity vector component.*/
|
/**
|
||||||
|
* Maximum absolute value of a velocity vector component.
|
||||||
|
*/
|
||||||
public static final float maxAbsVelocity = 127f / velocityPercision;
|
public static final float maxAbsVelocity = 127f / velocityPercision;
|
||||||
public static final float elevationScale = 4f;
|
public static final float elevationScale = 4f;
|
||||||
|
|
||||||
@@ -71,13 +77,13 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setCarrier(CarryTrait carrier) {
|
public CarryTrait getCarrier(){
|
||||||
this.carrier = carrier;
|
return carrier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CarryTrait getCarrier() {
|
public void setCarrier(CarryTrait carrier){
|
||||||
return carrier;
|
this.carrier = carrier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -201,14 +207,17 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
public void avoidOthers(float avoidRange){
|
public void avoidOthers(float avoidRange){
|
||||||
|
|
||||||
EntityPhysics.getNearby(getGroup(), x, y, avoidRange * 2f, t -> {
|
EntityPhysics.getNearby(getGroup(), x, y, avoidRange * 2f, t -> {
|
||||||
if(t == this || (t instanceof Unit && (((Unit) t).isDead() || (((Unit) t).isFlying() != isFlying()) || ((Unit) t).getCarrier() == this) || getCarrier() == t)) return;
|
if(t == this || (t instanceof Unit && (((Unit) t).isDead() || (((Unit) t).isFlying() != isFlying()) || ((Unit) t).getCarrier() == this) || getCarrier() == t))
|
||||||
|
return;
|
||||||
float dst = distanceTo(t);
|
float dst = distanceTo(t);
|
||||||
if(dst > avoidRange) return;
|
if(dst > avoidRange) return;
|
||||||
velocity.add(moveVector.set(x, y).sub(t.getX(), t.getY()).setLength(1f * (1f - (dst / avoidRange))));
|
velocity.add(moveVector.set(x, y).sub(t.getX(), t.getY()).setLength(1f * (1f - (dst / avoidRange))));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Updates velocity and status effects.*/
|
/**
|
||||||
|
* Updates velocity and status effects.
|
||||||
|
*/
|
||||||
public void updateVelocityStatus(float drag, float maxVelocity){
|
public void updateVelocityStatus(float drag, float maxVelocity){
|
||||||
if(isCarried()){ //carried units do not take into account velocity normally
|
if(isCarried()){ //carried units do not take into account velocity normally
|
||||||
set(carrier.getX(), carrier.getY());
|
set(carrier.getX(), carrier.getY());
|
||||||
@@ -302,9 +311,14 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
return inventory.totalAmmo() / (float) inventory.ammoCapacity();
|
return inventory.totalAmmo() / (float) inventory.ammoCapacity();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void drawUnder(){}
|
public void drawUnder(){
|
||||||
public void drawOver(){}
|
}
|
||||||
public void drawShadow(){}
|
|
||||||
|
public void drawOver(){
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawShadow(){
|
||||||
|
}
|
||||||
|
|
||||||
public void drawView(){
|
public void drawView(){
|
||||||
Fill.circle(x, y, getViewDistance());
|
Fill.circle(x, y, getViewDistance());
|
||||||
@@ -319,12 +333,20 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract TextureRegion getIconRegion();
|
public abstract TextureRegion getIconRegion();
|
||||||
|
|
||||||
public abstract int getItemCapacity();
|
public abstract int getItemCapacity();
|
||||||
|
|
||||||
public abstract int getAmmoCapacity();
|
public abstract int getAmmoCapacity();
|
||||||
|
|
||||||
public abstract float getArmor();
|
public abstract float getArmor();
|
||||||
|
|
||||||
public abstract boolean acceptsAmmo(Item item);
|
public abstract boolean acceptsAmmo(Item item);
|
||||||
|
|
||||||
public abstract void addAmmo(Item item);
|
public abstract void addAmmo(Item item);
|
||||||
|
|
||||||
public abstract float getMass();
|
public abstract float getMass();
|
||||||
|
|
||||||
public abstract boolean isFlying();
|
public abstract boolean isFlying();
|
||||||
|
|
||||||
public abstract float getSize();
|
public abstract float getSize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,15 +8,16 @@ import io.anuke.mindustry.type.AmmoType;
|
|||||||
import io.anuke.mindustry.type.Item;
|
import io.anuke.mindustry.type.Item;
|
||||||
import io.anuke.mindustry.type.ItemStack;
|
import io.anuke.mindustry.type.ItemStack;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.DataInput;
|
||||||
|
import java.io.DataOutput;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
public class UnitInventory implements Saveable{
|
public class UnitInventory implements Saveable{
|
||||||
|
private final Unit unit;
|
||||||
private Array<AmmoEntry> ammos = new Array<>();
|
private Array<AmmoEntry> ammos = new Array<>();
|
||||||
private int totalAmmo;
|
private int totalAmmo;
|
||||||
private ItemStack item = new ItemStack(Items.stone, 0);
|
private ItemStack item = new ItemStack(Items.stone, 0);
|
||||||
|
|
||||||
private final Unit unit;
|
|
||||||
|
|
||||||
public UnitInventory(Unit unit){
|
public UnitInventory(Unit unit){
|
||||||
this.unit = unit;
|
this.unit = unit;
|
||||||
}
|
}
|
||||||
@@ -53,7 +54,9 @@ public class UnitInventory implements Saveable{
|
|||||||
item.amount = iamount;
|
item.amount = iamount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns ammo range, or MAX_VALUE if this inventory has no ammo.*/
|
/**
|
||||||
|
* Returns ammo range, or MAX_VALUE if this inventory has no ammo.
|
||||||
|
*/
|
||||||
public float getAmmoRange(){
|
public float getAmmoRange(){
|
||||||
return hasAmmo() ? getAmmo().getRange() : Float.MAX_VALUE;
|
return hasAmmo() ? getAmmo().getRange() : Float.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,9 @@ import io.anuke.ucore.function.Predicate;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
/**Utility class for unit and team interactions.*/
|
/**
|
||||||
|
* Utility class for unit and team interactions.
|
||||||
|
*/
|
||||||
public class Units{
|
public class Units{
|
||||||
private static Rectangle rect = new Rectangle();
|
private static Rectangle rect = new Rectangle();
|
||||||
private static Rectangle hitrect = new Rectangle();
|
private static Rectangle hitrect = new Rectangle();
|
||||||
@@ -23,7 +25,9 @@ public class Units {
|
|||||||
private static float cdist;
|
private static float cdist;
|
||||||
private static boolean boolResult;
|
private static boolean boolResult;
|
||||||
|
|
||||||
/**Validates a target.
|
/**
|
||||||
|
* Validates a target.
|
||||||
|
*
|
||||||
* @param target The target to validate
|
* @param target The target to validate
|
||||||
* @param team The team of the thing doing tha targeting
|
* @param team The team of the thing doing tha targeting
|
||||||
* @param x The X position of the thing doign the targeting
|
* @param x The X position of the thing doign the targeting
|
||||||
@@ -36,17 +40,23 @@ public class Units {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
|
/**
|
||||||
|
* See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}
|
||||||
|
*/
|
||||||
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y){
|
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y){
|
||||||
return invalidateTarget(target, team, x, y, Float.MAX_VALUE);
|
return invalidateTarget(target, team, x, y, Float.MAX_VALUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
|
/**
|
||||||
|
* See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}
|
||||||
|
*/
|
||||||
public static boolean invalidateTarget(TargetTrait target, Unit targeter){
|
public static boolean invalidateTarget(TargetTrait target, Unit targeter){
|
||||||
return invalidateTarget(target, targeter.team, targeter.x, targeter.y, targeter.inventory.getAmmoRange());
|
return invalidateTarget(target, targeter.team, targeter.x, targeter.y, targeter.inventory.getAmmoRange());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether there are any entities on this tile.*/
|
/**
|
||||||
|
* Returns whether there are any entities on this tile.
|
||||||
|
*/
|
||||||
public static boolean anyEntities(Tile tile){
|
public static boolean anyEntities(Tile tile){
|
||||||
Block type = tile.block();
|
Block type = tile.block();
|
||||||
rect.setSize(type.size * tilesize, type.size * tilesize);
|
rect.setSize(type.size * tilesize, type.size * tilesize);
|
||||||
@@ -68,7 +78,9 @@ public class Units {
|
|||||||
return boolResult;
|
return boolResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether there are any entities on this tile, with the hitbox expanded.*/
|
/**
|
||||||
|
* Returns whether there are any entities on this tile, with the hitbox expanded.
|
||||||
|
*/
|
||||||
public static boolean anyEntities(Tile tile, float expansion, Predicate<Unit> pred){
|
public static boolean anyEntities(Tile tile, float expansion, Predicate<Unit> pred){
|
||||||
Block type = tile.block();
|
Block type = tile.block();
|
||||||
rect.setSize(type.size * tilesize + expansion, type.size * tilesize + expansion);
|
rect.setSize(type.size * tilesize + expansion, type.size * tilesize + expansion);
|
||||||
@@ -90,7 +102,9 @@ public class Units {
|
|||||||
return value[0];
|
return value[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the neareset ally tile in a range.*/
|
/**
|
||||||
|
* Returns the neareset ally tile in a range.
|
||||||
|
*/
|
||||||
public static TileEntity findAllyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
public static TileEntity findAllyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
||||||
for(Team enemy : state.teams.alliesOf(team)){
|
for(Team enemy : state.teams.alliesOf(team)){
|
||||||
TileEntity entity = world.indexer().findTile(enemy, x, y, range, pred);
|
TileEntity entity = world.indexer().findTile(enemy, x, y, range, pred);
|
||||||
@@ -101,7 +115,9 @@ public class Units {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the neareset enemy tile in a range.*/
|
/**
|
||||||
|
* Returns the neareset enemy tile in a range.
|
||||||
|
*/
|
||||||
public static TileEntity findEnemyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
public static TileEntity findEnemyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
||||||
for(Team enemy : state.teams.enemiesOf(team)){
|
for(Team enemy : state.teams.enemiesOf(team)){
|
||||||
TileEntity entity = world.indexer().findTile(enemy, x, y, range, pred);
|
TileEntity entity = world.indexer().findTile(enemy, x, y, range, pred);
|
||||||
@@ -112,7 +128,9 @@ public class Units {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Iterates over all units on all teams, including players.*/
|
/**
|
||||||
|
* Iterates over all units on all teams, including players.
|
||||||
|
*/
|
||||||
public static void allUnits(Consumer<Unit> cons){
|
public static void allUnits(Consumer<Unit> cons){
|
||||||
//check all unit groups first
|
//check all unit groups first
|
||||||
for(EntityGroup<BaseUnit> group : unitGroups){
|
for(EntityGroup<BaseUnit> group : unitGroups){
|
||||||
@@ -129,7 +147,9 @@ public class Units {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the closest target enemy. First, units are checked, then tile entities.*/
|
/**
|
||||||
|
* Returns the closest target enemy. First, units are checked, then tile entities.
|
||||||
|
*/
|
||||||
public static TargetTrait getClosestTarget(Team team, float x, float y, float range){
|
public static TargetTrait getClosestTarget(Team team, float x, float y, float range){
|
||||||
Unit unit = getClosestEnemy(team, x, y, range, u -> true);
|
Unit unit = getClosestEnemy(team, x, y, range, u -> true);
|
||||||
if(unit != null){
|
if(unit != null){
|
||||||
@@ -139,7 +159,9 @@ public class Units {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the closest enemy of this team. Filter by predicate.*/
|
/**
|
||||||
|
* Returns the closest enemy of this team. Filter by predicate.
|
||||||
|
*/
|
||||||
public static Unit getClosestEnemy(Team team, float x, float y, float range, Predicate<Unit> predicate){
|
public static Unit getClosestEnemy(Team team, float x, float y, float range, Predicate<Unit> predicate){
|
||||||
result = null;
|
result = null;
|
||||||
cdist = 0f;
|
cdist = 0f;
|
||||||
@@ -162,7 +184,9 @@ public class Units {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the closest ally of this team. Filter by predicate.*/
|
/**
|
||||||
|
* Returns the closest ally of this team. Filter by predicate.
|
||||||
|
*/
|
||||||
public static Unit getClosest(Team team, float x, float y, float range, Predicate<Unit> predicate){
|
public static Unit getClosest(Team team, float x, float y, float range, Predicate<Unit> predicate){
|
||||||
result = null;
|
result = null;
|
||||||
cdist = 0f;
|
cdist = 0f;
|
||||||
@@ -185,7 +209,9 @@ public class Units {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Iterates over all units in a rectangle.*/
|
/**
|
||||||
|
* Iterates over all units in a rectangle.
|
||||||
|
*/
|
||||||
public static void getNearby(Team team, Rectangle rect, Consumer<Unit> cons){
|
public static void getNearby(Team team, Rectangle rect, Consumer<Unit> cons){
|
||||||
|
|
||||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||||
@@ -199,7 +225,9 @@ public class Units {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Iterates over all units in a circle around this position.*/
|
/**
|
||||||
|
* Iterates over all units in a circle around this position.
|
||||||
|
*/
|
||||||
public static void getNearby(Team team, float x, float y, float radius, Consumer<Unit> cons){
|
public static void getNearby(Team team, float x, float y, float radius, Consumer<Unit> cons){
|
||||||
rect.setSize(radius * 2).setCenter(x, y);
|
rect.setSize(radius * 2).setCenter(x, y);
|
||||||
|
|
||||||
@@ -220,7 +248,9 @@ public class Units {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Iterates over all units in a rectangle.*/
|
/**
|
||||||
|
* Iterates over all units in a rectangle.
|
||||||
|
*/
|
||||||
public static void getNearby(Rectangle rect, Consumer<Unit> cons){
|
public static void getNearby(Rectangle rect, Consumer<Unit> cons){
|
||||||
|
|
||||||
for(Team team : Team.all){
|
for(Team team : Team.all){
|
||||||
@@ -234,7 +264,9 @@ public class Units {
|
|||||||
EntityPhysics.getNearby(playerGroup, rect, player -> cons.accept((Unit) player));
|
EntityPhysics.getNearby(playerGroup, rect, player -> cons.accept((Unit) player));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Iterates over all units that are enemies of this team.*/
|
/**
|
||||||
|
* Iterates over all units that are enemies of this team.
|
||||||
|
*/
|
||||||
public static void getNearbyEnemies(Team team, Rectangle rect, Consumer<Unit> cons){
|
public static void getNearbyEnemies(Team team, Rectangle rect, Consumer<Unit> cons){
|
||||||
ObjectSet<Team> targets = state.teams.enemiesOf(team);
|
ObjectSet<Team> targets = state.teams.enemiesOf(team);
|
||||||
|
|
||||||
@@ -253,7 +285,9 @@ public class Units {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Iterates over all units.*/
|
/**
|
||||||
|
* Iterates over all units.
|
||||||
|
*/
|
||||||
public static void getAllUnits(Consumer<Unit> cons){
|
public static void getAllUnits(Consumer<Unit> cons){
|
||||||
|
|
||||||
for(Team team : Team.all){
|
for(Team team : Team.all){
|
||||||
|
|||||||
@@ -12,7 +12,9 @@ import io.anuke.ucore.graphics.Draw;
|
|||||||
import io.anuke.ucore.util.Angles;
|
import io.anuke.ucore.util.Angles;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
|
||||||
/**A BulletType for most ammo-based bullets shot from turrets and units.*/
|
/**
|
||||||
|
* A BulletType for most ammo-based bullets shot from turrets and units.
|
||||||
|
*/
|
||||||
public class BasicBulletType extends BulletType{
|
public class BasicBulletType extends BulletType{
|
||||||
public Color backColor = Palette.bulletYellowBack, frontColor = Palette.bulletYellow;
|
public Color backColor = Palette.bulletYellowBack, frontColor = Palette.bulletYellow;
|
||||||
public float bulletWidth = 5f, bulletHeight = 7f;
|
public float bulletWidth = 5f, bulletHeight = 7f;
|
||||||
@@ -23,7 +25,9 @@ public class BasicBulletType extends BulletType {
|
|||||||
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f;
|
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f;
|
||||||
public BulletType fragBullet = null;
|
public BulletType fragBullet = null;
|
||||||
|
|
||||||
/**Use a negative value to disable splash damage.*/
|
/**
|
||||||
|
* Use a negative value to disable splash damage.
|
||||||
|
*/
|
||||||
public float splashDamageRadius = -1f;
|
public float splashDamageRadius = -1f;
|
||||||
public float splashDamage = 6f;
|
public float splashDamage = 6f;
|
||||||
|
|
||||||
|
|||||||
@@ -28,12 +28,16 @@ import static io.anuke.mindustry.Vars.world;
|
|||||||
|
|
||||||
public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncTrait{
|
public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncTrait{
|
||||||
private static Vector2 vector = new Vector2();
|
private static Vector2 vector = new Vector2();
|
||||||
|
public Timer timer = new Timer(3);
|
||||||
private Team team;
|
private Team team;
|
||||||
private Object data;
|
private Object data;
|
||||||
private boolean supressCollision;
|
private boolean supressCollision;
|
||||||
|
|
||||||
public Timer timer = new Timer(3);
|
/**
|
||||||
|
* Internal use only!
|
||||||
|
*/
|
||||||
|
public Bullet(){
|
||||||
|
}
|
||||||
|
|
||||||
public static void create(BulletType type, TeamTrait owner, float x, float y, float angle){
|
public static void create(BulletType type, TeamTrait owner, float x, float y, float angle){
|
||||||
create(type, owner, owner.getTeam(), x, y, angle);
|
create(type, owner, owner.getTeam(), x, y, angle);
|
||||||
@@ -86,9 +90,6 @@ public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncT
|
|||||||
create(type, null, Team.none, x, y, angle);
|
create(type, null, Team.none, x, y, angle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Internal use only!*/
|
|
||||||
public Bullet(){}
|
|
||||||
|
|
||||||
public boolean collidesTiles(){
|
public boolean collidesTiles(){
|
||||||
return type.collidesTiles;
|
return type.collidesTiles;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,23 +13,41 @@ public abstract class BulletType extends BaseBulletType<Bullet> implements Conte
|
|||||||
private static Array<BulletType> types = new Array<>();
|
private static Array<BulletType> types = new Array<>();
|
||||||
|
|
||||||
public final int id;
|
public final int id;
|
||||||
/**Knockback in velocity.*/
|
/**
|
||||||
|
* Knockback in velocity.
|
||||||
|
*/
|
||||||
public float knockback;
|
public float knockback;
|
||||||
/**Whether this bullet hits tiles.*/
|
/**
|
||||||
|
* Whether this bullet hits tiles.
|
||||||
|
*/
|
||||||
public boolean hitTiles = true;
|
public boolean hitTiles = true;
|
||||||
/**Status effect applied on hit.*/
|
/**
|
||||||
|
* Status effect applied on hit.
|
||||||
|
*/
|
||||||
public StatusEffect status = StatusEffects.none;
|
public StatusEffect status = StatusEffects.none;
|
||||||
/**Intensity of applied status effect in terms of duration.*/
|
/**
|
||||||
|
* Intensity of applied status effect in terms of duration.
|
||||||
|
*/
|
||||||
public float statusIntensity = 0.5f;
|
public float statusIntensity = 0.5f;
|
||||||
/**What fraction of armor is pierced, 0-1*/
|
/**
|
||||||
|
* What fraction of armor is pierced, 0-1
|
||||||
|
*/
|
||||||
public float armorPierce = 0f;
|
public float armorPierce = 0f;
|
||||||
/**Whether to sync this bullet to clients.*/
|
/**
|
||||||
|
* Whether to sync this bullet to clients.
|
||||||
|
*/
|
||||||
public boolean syncable;
|
public boolean syncable;
|
||||||
/**Whether this bullet type collides with tiles.*/
|
/**
|
||||||
|
* Whether this bullet type collides with tiles.
|
||||||
|
*/
|
||||||
public boolean collidesTiles = true;
|
public boolean collidesTiles = true;
|
||||||
/**Whether this bullet types collides with anything at all.*/
|
/**
|
||||||
|
* Whether this bullet types collides with anything at all.
|
||||||
|
*/
|
||||||
public boolean collides = true;
|
public boolean collides = true;
|
||||||
/**Whether velocity is inherited from the shooter.*/
|
/**
|
||||||
|
* Whether velocity is inherited from the shooter.
|
||||||
|
*/
|
||||||
public boolean keepVelocity = true;
|
public boolean keepVelocity = true;
|
||||||
|
|
||||||
public BulletType(float speed, float damage){
|
public BulletType(float speed, float damage){
|
||||||
@@ -43,6 +61,14 @@ public abstract class BulletType extends BaseBulletType<Bullet> implements Conte
|
|||||||
types.add(this);
|
types.add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BulletType getByID(int id){
|
||||||
|
return types.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Array<BulletType> all(){
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hit(Bullet b, float hitx, float hity){
|
public void hit(Bullet b, float hitx, float hity){
|
||||||
Effects.effect(hiteffect, hitx, hity, b.angle());
|
Effects.effect(hiteffect, hitx, hity, b.angle());
|
||||||
@@ -62,12 +88,4 @@ public abstract class BulletType extends BaseBulletType<Bullet> implements Conte
|
|||||||
public Array<? extends Content> getAll(){
|
public Array<? extends Content> getAll(){
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BulletType getByID(int id){
|
|
||||||
return types.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Array<BulletType> all(){
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ import io.anuke.ucore.util.Mathf;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.groundEffectGroup;
|
import static io.anuke.mindustry.Vars.groundEffectGroup;
|
||||||
|
|
||||||
/**Class for creating block rubble on the ground.*/
|
/**
|
||||||
|
* Class for creating block rubble on the ground.
|
||||||
|
*/
|
||||||
public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait{
|
public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait{
|
||||||
private static final Color color = Color.valueOf("52504e");
|
private static final Color color = Color.valueOf("52504e");
|
||||||
|
|
||||||
|
|||||||
@@ -41,7 +41,15 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
|||||||
private float baseFlammability = -1, puddleFlammability;
|
private float baseFlammability = -1, puddleFlammability;
|
||||||
private float lifetime;
|
private float lifetime;
|
||||||
|
|
||||||
/**Start a fire on the tile. If there already is a file there, refreshes its lifetime.*/
|
/**
|
||||||
|
* Deserialization use only!
|
||||||
|
*/
|
||||||
|
public Fire(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a fire on the tile. If there already is a file there, refreshes its lifetime.
|
||||||
|
*/
|
||||||
public static void create(Tile tile){
|
public static void create(Tile tile){
|
||||||
if(Net.client() || tile == null) return; //not clientside.
|
if(Net.client() || tile == null) return; //not clientside.
|
||||||
|
|
||||||
@@ -60,15 +68,19 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing.*/
|
/**
|
||||||
|
* Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing.
|
||||||
|
*/
|
||||||
public static void extinguish(Tile tile, float intensity){
|
public static void extinguish(Tile tile, float intensity){
|
||||||
if(tile != null && map.containsKey(tile.packedPosition())){
|
if(tile != null && map.containsKey(tile.packedPosition())){
|
||||||
map.get(tile.packedPosition()).time += intensity * Timers.delta();
|
map.get(tile.packedPosition()).time += intensity * Timers.delta();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Deserialization use only!*/
|
@Remote(called = Loc.server, in = In.entities)
|
||||||
public Fire(){}
|
public static void onFireRemoved(int fireid){
|
||||||
|
fireGroup.removeByID(fireid);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float lifetime(){
|
public float lifetime(){
|
||||||
@@ -196,9 +208,4 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
|||||||
public EntityGroup targetGroup(){
|
public EntityGroup targetGroup(){
|
||||||
return fireGroup;
|
return fireGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(called = Loc.server, in = In.entities)
|
|
||||||
public static void onFireRemoved(int fireid){
|
|
||||||
fireGroup.removeByID(fireid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ import io.anuke.ucore.entities.impl.EffectEntity;
|
|||||||
import io.anuke.ucore.function.EffectRenderer;
|
import io.anuke.ucore.function.EffectRenderer;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
|
||||||
/**A ground effect contains an effect that is rendered on the ground layer as opposed to the top layer.*/
|
/**
|
||||||
|
* A ground effect contains an effect that is rendered on the ground layer as opposed to the top layer.
|
||||||
|
*/
|
||||||
public class GroundEffectEntity extends EffectEntity{
|
public class GroundEffectEntity extends EffectEntity{
|
||||||
private boolean once;
|
private boolean once;
|
||||||
|
|
||||||
@@ -53,12 +55,18 @@ public class GroundEffectEntity extends EffectEntity {
|
|||||||
once = false;
|
once = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**An effect that is rendered on the ground layer as opposed to the top layer.*/
|
/**
|
||||||
|
* An effect that is rendered on the ground layer as opposed to the top layer.
|
||||||
|
*/
|
||||||
public static class GroundEffect extends Effect{
|
public static class GroundEffect extends Effect{
|
||||||
/**How long this effect stays on the ground when static.*/
|
/**
|
||||||
|
* How long this effect stays on the ground when static.
|
||||||
|
*/
|
||||||
public final float staticLife;
|
public final float staticLife;
|
||||||
/**If true, this effect will stop and lie on the ground for a specific duration,
|
/**
|
||||||
* after its initial lifetime is over.*/
|
* If true, this effect will stop and lie on the ground for a specific duration,
|
||||||
|
* after its initial lifetime is over.
|
||||||
|
*/
|
||||||
public final boolean isStatic;
|
public final boolean isStatic;
|
||||||
|
|
||||||
public GroundEffect(float life, float staticLife, EffectRenderer draw){
|
public GroundEffect(float life, float staticLife, EffectRenderer draw){
|
||||||
|
|||||||
@@ -46,6 +46,14 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
|
|||||||
private float time;
|
private float time;
|
||||||
private float sinktime;
|
private float sinktime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal use only!
|
||||||
|
*/
|
||||||
|
public ItemDrop(){
|
||||||
|
hitbox.setSize(5f);
|
||||||
|
hitboxTile.setSize(5f);
|
||||||
|
}
|
||||||
|
|
||||||
public static ItemDrop create(Item item, int amount, float x, float y, float angle){
|
public static ItemDrop create(Item item, int amount, float x, float y, float angle){
|
||||||
ItemDrop drop = new ItemDrop();
|
ItemDrop drop = new ItemDrop();
|
||||||
drop.item = item;
|
drop.item = item;
|
||||||
@@ -73,12 +81,6 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Internal use only!*/
|
|
||||||
public ItemDrop(){
|
|
||||||
hitbox.setSize(5f);
|
|
||||||
hitboxTile.setSize(5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Item getItem(){
|
public Item getItem(){
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,17 +32,22 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
|||||||
private PosTrait to;
|
private PosTrait to;
|
||||||
private Runnable done;
|
private Runnable done;
|
||||||
|
|
||||||
|
public ItemTransfer(){
|
||||||
|
}
|
||||||
|
|
||||||
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
||||||
public static void transferAmmo(Item item, float x, float y, Unit to){
|
public static void transferAmmo(Item item, float x, float y, Unit to){
|
||||||
if(to == null) return;
|
if(to == null) return;
|
||||||
to.addAmmo(item);
|
to.addAmmo(item);
|
||||||
create(item, x, y, to, () -> {});
|
create(item, x, y, to, () -> {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
||||||
public static void transferItemEffect(Item item, float x, float y, Unit to){
|
public static void transferItemEffect(Item item, float x, float y, Unit to){
|
||||||
if(to == null) return;
|
if(to == null) return;
|
||||||
create(item, x, y, to, () -> {});
|
create(item, x, y, to, () -> {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
||||||
@@ -55,7 +60,8 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
|||||||
public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){
|
public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){
|
||||||
if(tile == null) return;
|
if(tile == null) return;
|
||||||
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
|
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
|
||||||
Timers.run(i*3, () -> create(item, x, y, tile, () -> {}));
|
Timers.run(i * 3, () -> create(item, x, y, tile, () -> {
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
tile.entity.items.add(item, amount);
|
tile.entity.items.add(item, amount);
|
||||||
}
|
}
|
||||||
@@ -70,8 +76,6 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
|||||||
tr.add();
|
tr.add();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemTransfer(){}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public float lifetime(){
|
public float lifetime(){
|
||||||
return 60;
|
return 60;
|
||||||
|
|||||||
@@ -46,7 +46,15 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT
|
|||||||
private Color color = Palette.lancerLaser;
|
private Color color = Palette.lancerLaser;
|
||||||
private SeedRandom random = new SeedRandom();
|
private SeedRandom random = new SeedRandom();
|
||||||
|
|
||||||
/**Create a lighting branch at a location. Use Team.none to damage everyone.*/
|
/**
|
||||||
|
* For pooling use only. Do not call directly!
|
||||||
|
*/
|
||||||
|
public Lightning(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a lighting branch at a location. Use Team.none to damage everyone.
|
||||||
|
*/
|
||||||
public static void create(Team team, Effect effect, Color color, float damage, float x, float y, float targetAngle, int length){
|
public static void create(Team team, Effect effect, Color color, float damage, float x, float y, float targetAngle, int length){
|
||||||
CallEntity.createLighting(lastSeed++, team, effect, color, damage, x, y, targetAngle, length);
|
CallEntity.createLighting(lastSeed++, team, effect, color, damage, x, y, targetAngle, length);
|
||||||
}
|
}
|
||||||
@@ -115,9 +123,6 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT
|
|||||||
l.add();
|
l.add();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**For pooling use only. Do not call directly!*/
|
|
||||||
public Lightning(){}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSyncing(){
|
public boolean isSyncing(){
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -58,17 +58,29 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
|||||||
private float accepting;
|
private float accepting;
|
||||||
private byte generation;
|
private byte generation;
|
||||||
|
|
||||||
/**Deposists a puddle between tile and source.*/
|
/**
|
||||||
|
* Deserialization use only!
|
||||||
|
*/
|
||||||
|
public Puddle(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deposists a puddle between tile and source.
|
||||||
|
*/
|
||||||
public static void deposit(Tile tile, Tile source, Liquid liquid, float amount){
|
public static void deposit(Tile tile, Tile source, Liquid liquid, float amount){
|
||||||
deposit(tile, source, liquid, amount, 0);
|
deposit(tile, source, liquid, amount, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Deposists a puddle at a tile.*/
|
/**
|
||||||
|
* Deposists a puddle at a tile.
|
||||||
|
*/
|
||||||
public static void deposit(Tile tile, Liquid liquid, float amount){
|
public static void deposit(Tile tile, Liquid liquid, float amount){
|
||||||
deposit(tile, tile, liquid, amount, 0);
|
deposit(tile, tile, liquid, amount, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the puddle on the specified tile. May return null.*/
|
/**
|
||||||
|
* Returns the puddle on the specified tile. May return null.
|
||||||
|
*/
|
||||||
public static Puddle getPuddle(Tile tile){
|
public static Puddle getPuddle(Tile tile){
|
||||||
return map.get(tile.packedPosition());
|
return map.get(tile.packedPosition());
|
||||||
}
|
}
|
||||||
@@ -108,13 +120,17 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether the first liquid can 'stay' on the second one.
|
/**
|
||||||
* Currently, the only place where this can happen is oil on water.*/
|
* Returns whether the first liquid can 'stay' on the second one.
|
||||||
|
* Currently, the only place where this can happen is oil on water.
|
||||||
|
*/
|
||||||
private static boolean canStayOn(Liquid liquid, Liquid other){
|
private static boolean canStayOn(Liquid liquid, Liquid other){
|
||||||
return liquid == Liquids.oil && other == Liquids.water;
|
return liquid == Liquids.oil && other == Liquids.water;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Reacts two liquids together at a location.*/
|
/**
|
||||||
|
* Reacts two liquids together at a location.
|
||||||
|
*/
|
||||||
private static float reactPuddle(Liquid dest, Liquid liquid, float amount, Tile tile, float x, float y){
|
private static float reactPuddle(Liquid dest, Liquid liquid, float amount, Tile tile, float x, float y){
|
||||||
if((dest.flammability > 0.3f && liquid.temperature > 0.7f) ||
|
if((dest.flammability > 0.3f && liquid.temperature > 0.7f) ||
|
||||||
(liquid.flammability > 0.3f && dest.temperature > 0.7f)){ //flammable liquid + hot liquid
|
(liquid.flammability > 0.3f && dest.temperature > 0.7f)){ //flammable liquid + hot liquid
|
||||||
@@ -136,8 +152,10 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
|||||||
return 0f;
|
return 0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Deserialization use only!*/
|
@Remote(called = Loc.server, in = In.entities)
|
||||||
public Puddle(){}
|
public static void onPuddleRemoved(int puddleid){
|
||||||
|
puddleGroup.removeByID(puddleid);
|
||||||
|
}
|
||||||
|
|
||||||
public float getFlammability(){
|
public float getFlammability(){
|
||||||
return liquid.flammability * amount;
|
return liquid.flammability * amount;
|
||||||
@@ -293,9 +311,4 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
|||||||
public EntityGroup targetGroup(){
|
public EntityGroup targetGroup(){
|
||||||
return puddleGroup;
|
return puddleGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(called = Loc.server, in = In.entities)
|
|
||||||
public static void onPuddleRemoved(int puddleid){
|
|
||||||
puddleGroup.removeByID(puddleid);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import io.anuke.ucore.util.Mathf;
|
|||||||
public class RubbleDecal extends Decal{
|
public class RubbleDecal extends Decal{
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
/**Creates a rubble effect at a position. Provide a block size to use.*/
|
/**
|
||||||
|
* Creates a rubble effect at a position. Provide a block size to use.
|
||||||
|
*/
|
||||||
public static void create(float x, float y, int size){
|
public static void create(float x, float y, int size){
|
||||||
RubbleDecal decal = new RubbleDecal();
|
RubbleDecal decal = new RubbleDecal();
|
||||||
decal.size = size;
|
decal.size = size;
|
||||||
|
|||||||
@@ -14,12 +14,11 @@ import static io.anuke.mindustry.Vars.shieldGroup;
|
|||||||
|
|
||||||
//todo re-implement
|
//todo re-implement
|
||||||
public class Shield extends BaseEntity implements DrawTrait{
|
public class Shield extends BaseEntity implements DrawTrait{
|
||||||
|
private final Tile tile;
|
||||||
public boolean active;
|
public boolean active;
|
||||||
public boolean hitPlayers = false;
|
public boolean hitPlayers = false;
|
||||||
public float radius = 0f;
|
public float radius = 0f;
|
||||||
|
|
||||||
private float uptime = 0f;
|
private float uptime = 0f;
|
||||||
private final Tile tile;
|
|
||||||
|
|
||||||
public Shield(Tile tile){
|
public Shield(Tile tile){
|
||||||
this.tile = tile;
|
this.tile = tile;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package io.anuke.mindustry.entities.traits;
|
package io.anuke.mindustry.entities.traits;
|
||||||
|
|
||||||
/**A flag interface for marking an effect as appearing below liquids.*/
|
/**
|
||||||
|
* A flag interface for marking an effect as appearing below liquids.
|
||||||
|
*/
|
||||||
public interface BelowLiquidTrait{
|
public interface BelowLiquidTrait{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,29 +36,43 @@ import java.util.Arrays;
|
|||||||
import static io.anuke.mindustry.Vars.tilesize;
|
import static io.anuke.mindustry.Vars.tilesize;
|
||||||
import static io.anuke.mindustry.Vars.world;
|
import static io.anuke.mindustry.Vars.world;
|
||||||
|
|
||||||
/**Interface for units that build, break or mine things.*/
|
/**
|
||||||
|
* Interface for units that build, break or mine things.
|
||||||
|
*/
|
||||||
public interface BuilderTrait extends Entity{
|
public interface BuilderTrait extends Entity{
|
||||||
//these are not instance variables!
|
//these are not instance variables!
|
||||||
Translator[] tmptr = {new Translator(), new Translator(), new Translator(), new Translator()};
|
Translator[] tmptr = {new Translator(), new Translator(), new Translator(), new Translator()};
|
||||||
float placeDistance = 140f;
|
float placeDistance = 140f;
|
||||||
float mineDistance = 70f;
|
float mineDistance = 70f;
|
||||||
|
|
||||||
/**Returns the queue for storing build requests.*/
|
/**
|
||||||
|
* Returns the queue for storing build requests.
|
||||||
|
*/
|
||||||
Queue<BuildRequest> getPlaceQueue();
|
Queue<BuildRequest> getPlaceQueue();
|
||||||
|
|
||||||
/**Returns the tile this builder is currently mining.*/
|
/**
|
||||||
|
* Returns the tile this builder is currently mining.
|
||||||
|
*/
|
||||||
Tile getMineTile();
|
Tile getMineTile();
|
||||||
|
|
||||||
/**Sets the tile this builder is currently mining.*/
|
/**
|
||||||
|
* Sets the tile this builder is currently mining.
|
||||||
|
*/
|
||||||
void setMineTile(Tile tile);
|
void setMineTile(Tile tile);
|
||||||
|
|
||||||
/**Returns the minining speed of this miner. 1 = standard, 0.5 = half speed, 2 = double speed, etc.*/
|
/**
|
||||||
|
* Returns the minining speed of this miner. 1 = standard, 0.5 = half speed, 2 = double speed, etc.
|
||||||
|
*/
|
||||||
float getMinePower();
|
float getMinePower();
|
||||||
|
|
||||||
/**Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all.*/
|
/**
|
||||||
|
* Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all.
|
||||||
|
*/
|
||||||
float getBuildPower(Tile tile);
|
float getBuildPower(Tile tile);
|
||||||
|
|
||||||
/**Whether this type of builder can begin creating new blocks.*/
|
/**
|
||||||
|
* Whether this type of builder can begin creating new blocks.
|
||||||
|
*/
|
||||||
default boolean canCreateBlocks(){
|
default boolean canCreateBlocks(){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -106,13 +120,17 @@ public interface BuilderTrait extends Entity{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Return whether this builder's place queue contains items.*/
|
/**
|
||||||
|
* Return whether this builder's place queue contains items.
|
||||||
|
*/
|
||||||
default boolean isBuilding(){
|
default boolean isBuilding(){
|
||||||
return getPlaceQueue().size != 0;
|
return getPlaceQueue().size != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**If a place request matching this signature is present, it is removed.
|
/**
|
||||||
* Otherwise, a new place request is added to the queue.*/
|
* If a place request matching this signature is present, it is removed.
|
||||||
|
* Otherwise, a new place request is added to the queue.
|
||||||
|
*/
|
||||||
default void replaceBuilding(int x, int y, int rotation, Recipe recipe){
|
default void replaceBuilding(int x, int y, int rotation, Recipe recipe){
|
||||||
synchronized(getPlaceQueue()){
|
synchronized(getPlaceQueue()){
|
||||||
for(BuildRequest request : getPlaceQueue()){
|
for(BuildRequest request : getPlaceQueue()){
|
||||||
@@ -127,12 +145,16 @@ public interface BuilderTrait extends Entity{
|
|||||||
addBuildRequest(new BuildRequest(x, y, rotation, recipe));
|
addBuildRequest(new BuildRequest(x, y, rotation, recipe));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Clears the placement queue.*/
|
/**
|
||||||
|
* Clears the placement queue.
|
||||||
|
*/
|
||||||
default void clearBuilding(){
|
default void clearBuilding(){
|
||||||
getPlaceQueue().clear();
|
getPlaceQueue().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Add another build requests to the tail of the queue, if it doesn't exist there yet.*/
|
/**
|
||||||
|
* Add another build requests to the tail of the queue, if it doesn't exist there yet.
|
||||||
|
*/
|
||||||
default void addBuildRequest(BuildRequest place){
|
default void addBuildRequest(BuildRequest place){
|
||||||
synchronized(getPlaceQueue()){
|
synchronized(getPlaceQueue()){
|
||||||
for(BuildRequest request : getPlaceQueue()){
|
for(BuildRequest request : getPlaceQueue()){
|
||||||
@@ -144,16 +166,20 @@ public interface BuilderTrait extends Entity{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Return the build requests currently active, or the one at the top of the queue.
|
/**
|
||||||
* May return null.*/
|
* Return the build requests currently active, or the one at the top of the queue.
|
||||||
|
* May return null.
|
||||||
|
*/
|
||||||
default BuildRequest getCurrentRequest(){
|
default BuildRequest getCurrentRequest(){
|
||||||
synchronized(getPlaceQueue()){
|
synchronized(getPlaceQueue()){
|
||||||
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
|
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Update building mechanism for this unit.
|
/**
|
||||||
* This includes mining.*/
|
* Update building mechanism for this unit.
|
||||||
|
* This includes mining.
|
||||||
|
*/
|
||||||
default void updateBuilding(Unit unit){
|
default void updateBuilding(Unit unit){
|
||||||
BuildRequest current = getCurrentRequest();
|
BuildRequest current = getCurrentRequest();
|
||||||
|
|
||||||
@@ -203,7 +229,9 @@ public interface BuilderTrait extends Entity{
|
|||||||
current.progress = entity.progress();
|
current.progress = entity.progress();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Do not call directly.*/
|
/**
|
||||||
|
* Do not call directly.
|
||||||
|
*/
|
||||||
default void updateMining(Unit unit){
|
default void updateMining(Unit unit){
|
||||||
Tile tile = getMineTile();
|
Tile tile = getMineTile();
|
||||||
|
|
||||||
@@ -229,7 +257,9 @@ public interface BuilderTrait extends Entity{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Draw placement effects for an entity. This includes mining*/
|
/**
|
||||||
|
* Draw placement effects for an entity. This includes mining
|
||||||
|
*/
|
||||||
default void drawBuilding(Unit unit){
|
default void drawBuilding(Unit unit){
|
||||||
BuildRequest request;
|
BuildRequest request;
|
||||||
|
|
||||||
@@ -286,7 +316,9 @@ public interface BuilderTrait extends Entity{
|
|||||||
Draw.color();
|
Draw.color();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Internal use only.*/
|
/**
|
||||||
|
* Internal use only.
|
||||||
|
*/
|
||||||
default void drawMining(Unit unit){
|
default void drawMining(Unit unit){
|
||||||
Tile tile = getMineTile();
|
Tile tile = getMineTile();
|
||||||
|
|
||||||
@@ -313,7 +345,9 @@ public interface BuilderTrait extends Entity{
|
|||||||
Draw.color();
|
Draw.color();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Class for storing build requests. Can be either a place or remove request.*/
|
/**
|
||||||
|
* Class for storing build requests. Can be either a place or remove request.
|
||||||
|
*/
|
||||||
class BuildRequest{
|
class BuildRequest{
|
||||||
public final int x, y, rotation;
|
public final int x, y, rotation;
|
||||||
public final Recipe recipe;
|
public final Recipe recipe;
|
||||||
@@ -321,7 +355,9 @@ public interface BuilderTrait extends Entity{
|
|||||||
|
|
||||||
public float progress;
|
public float progress;
|
||||||
|
|
||||||
/**This creates a build request.*/
|
/**
|
||||||
|
* This creates a build request.
|
||||||
|
*/
|
||||||
public BuildRequest(int x, int y, int rotation, Recipe recipe){
|
public BuildRequest(int x, int y, int rotation, Recipe recipe){
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
@@ -330,7 +366,9 @@ public interface BuilderTrait extends Entity{
|
|||||||
this.remove = false;
|
this.remove = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**This creates a remove request.*/
|
/**
|
||||||
|
* This creates a remove request.
|
||||||
|
*/
|
||||||
public BuildRequest(int x, int y){
|
public BuildRequest(int x, int y){
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public interface CarriableTrait extends TeamTrait, TargetTrait, SolidTrait{
|
|||||||
return getCarrier() != null;
|
return getCarrier() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setCarrier(CarryTrait carrier);
|
|
||||||
CarryTrait getCarrier();
|
CarryTrait getCarrier();
|
||||||
|
|
||||||
|
void setCarrier(CarryTrait carrier);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,28 +10,6 @@ import io.anuke.ucore.core.Effects;
|
|||||||
import io.anuke.ucore.entities.trait.SolidTrait;
|
import io.anuke.ucore.entities.trait.SolidTrait;
|
||||||
|
|
||||||
public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{
|
public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{
|
||||||
/**Returns the thing this carrier is carrying.*/
|
|
||||||
CarriableTrait getCarry();
|
|
||||||
/**Sets the carrying unit. Internal use only! Use {@link #carry(CarriableTrait)} to set state.*/
|
|
||||||
void setCarry(CarriableTrait unit);
|
|
||||||
/**Returns maximum mass this carrier can carry.*/
|
|
||||||
float getCarryWeight();
|
|
||||||
|
|
||||||
/**Drops the unit that is being carried, if applicable.*/
|
|
||||||
default void dropCarry(){
|
|
||||||
carry(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
default void dropCarryLocal(){
|
|
||||||
setCarryOf(null, this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Do not override unless absolutely necessary.
|
|
||||||
* Carries a unit. To drop a unit, call with {@code null}.*/
|
|
||||||
default void carry(CarriableTrait unit){
|
|
||||||
CallEntity.setCarryOf(this instanceof Player ? (Player)this : null, this, unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(called = Loc.both, targets = Loc.both, forward = true, in = In.entities)
|
@Remote(called = Loc.both, targets = Loc.both, forward = true, in = In.entities)
|
||||||
static void dropSelf(Player player){
|
static void dropSelf(Player player){
|
||||||
if(player.getCarrier() != null){
|
if(player.getCarrier() != null){
|
||||||
@@ -62,4 +40,38 @@ public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{
|
|||||||
Effects.effect(UnitFx.unitPickup, trait);
|
Effects.effect(UnitFx.unitPickup, trait);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the thing this carrier is carrying.
|
||||||
|
*/
|
||||||
|
CarriableTrait getCarry();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the carrying unit. Internal use only! Use {@link #carry(CarriableTrait)} to set state.
|
||||||
|
*/
|
||||||
|
void setCarry(CarriableTrait unit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns maximum mass this carrier can carry.
|
||||||
|
*/
|
||||||
|
float getCarryWeight();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drops the unit that is being carried, if applicable.
|
||||||
|
*/
|
||||||
|
default void dropCarry(){
|
||||||
|
carry(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
default void dropCarryLocal(){
|
||||||
|
setCarryOf(null, this, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do not override unless absolutely necessary.
|
||||||
|
* Carries a unit. To drop a unit, call with {@code null}.
|
||||||
|
*/
|
||||||
|
default void carry(CarriableTrait unit){
|
||||||
|
CallEntity.setCarryOf(this instanceof Player ? (Player) this : null, this, unit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package io.anuke.mindustry.entities.traits;
|
|||||||
|
|
||||||
import io.anuke.ucore.entities.trait.Entity;
|
import io.anuke.ucore.entities.trait.Entity;
|
||||||
|
|
||||||
/**Marks an entity as serializable.*/
|
/**
|
||||||
|
* Marks an entity as serializable.
|
||||||
|
*/
|
||||||
public interface SaveTrait extends Entity, TypeTrait, Saveable{
|
public interface SaveTrait extends Entity, TypeTrait, Saveable{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ import java.io.IOException;
|
|||||||
|
|
||||||
public interface Saveable{
|
public interface Saveable{
|
||||||
void writeSave(DataOutput stream) throws IOException;
|
void writeSave(DataOutput stream) throws IOException;
|
||||||
|
|
||||||
void readSave(DataInput stream) throws IOException;
|
void readSave(DataInput stream) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import io.anuke.ucore.util.Timer;
|
|||||||
public interface ShooterTrait extends VelocityTrait, TeamTrait, InventoryTrait{
|
public interface ShooterTrait extends VelocityTrait, TeamTrait, InventoryTrait{
|
||||||
|
|
||||||
Timer getTimer();
|
Timer getTimer();
|
||||||
|
|
||||||
int getShootTimer(boolean left);
|
int getShootTimer(boolean left);
|
||||||
|
|
||||||
Weapon getWeapon();
|
Weapon getWeapon();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import io.anuke.mindustry.world.Tile;
|
|||||||
|
|
||||||
public interface SpawnerTrait{
|
public interface SpawnerTrait{
|
||||||
Tile getTile();
|
Tile getTile();
|
||||||
|
|
||||||
void updateSpawning(Unit unit);
|
void updateSpawning(Unit unit);
|
||||||
|
|
||||||
float getSpawnProgress();
|
float getSpawnProgress();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,16 @@ import static io.anuke.mindustry.Vars.threads;
|
|||||||
|
|
||||||
public interface SyncTrait extends Entity, TypeTrait{
|
public interface SyncTrait extends Entity, TypeTrait{
|
||||||
|
|
||||||
/**Whether smoothing of entities is enabled when using multithreading; not yet implemented.*/
|
/**
|
||||||
|
* Whether smoothing of entities is enabled when using multithreading; not yet implemented.
|
||||||
|
*/
|
||||||
static boolean isSmoothing(){
|
static boolean isSmoothing(){
|
||||||
return threads.isEnabled() && threads.getTPS() <= Gdx.graphics.getFramesPerSecond() / 2f;
|
return threads.isEnabled() && threads.getTPS() <= Gdx.graphics.getFramesPerSecond() / 2f;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sets the position of this entity and updated the interpolator.*/
|
/**
|
||||||
|
* Sets the position of this entity and updated the interpolator.
|
||||||
|
*/
|
||||||
default void setNet(float x, float y){
|
default void setNet(float x, float y){
|
||||||
set(x, y);
|
set(x, y);
|
||||||
|
|
||||||
@@ -30,9 +34,12 @@ public interface SyncTrait extends Entity, TypeTrait {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Interpolate entity position only. Override if you need to interpolate rotations or other values.*/
|
/**
|
||||||
|
* Interpolate entity position only. Override if you need to interpolate rotations or other values.
|
||||||
|
*/
|
||||||
default void interpolate(){
|
default void interpolate(){
|
||||||
if(getInterpolator() == null) throw new RuntimeException("This entity must have an interpolator to interpolate()!");
|
if(getInterpolator() == null)
|
||||||
|
throw new RuntimeException("This entity must have an interpolator to interpolate()!");
|
||||||
|
|
||||||
getInterpolator().update();
|
getInterpolator().update();
|
||||||
|
|
||||||
@@ -40,17 +47,22 @@ public interface SyncTrait extends Entity, TypeTrait {
|
|||||||
setY(getInterpolator().pos.y);
|
setY(getInterpolator().pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Return the interpolator used for smoothing the position. Optional.*/
|
/**
|
||||||
|
* Return the interpolator used for smoothing the position. Optional.
|
||||||
|
*/
|
||||||
default Interpolator getInterpolator(){
|
default Interpolator getInterpolator(){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Whether syncing is enabled for this entity; true by default.*/
|
/**
|
||||||
|
* Whether syncing is enabled for this entity; true by default.
|
||||||
|
*/
|
||||||
default boolean isSyncing(){
|
default boolean isSyncing(){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//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;
|
||||||
|
|
||||||
void read(DataInput data, long time) throws IOException;
|
void read(DataInput data, long time) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,21 @@
|
|||||||
package io.anuke.mindustry.entities.traits;
|
package io.anuke.mindustry.entities.traits;
|
||||||
|
|
||||||
import io.anuke.mindustry.game.Team;
|
import io.anuke.mindustry.game.Team;
|
||||||
import io.anuke.ucore.entities.trait.VelocityTrait;
|
|
||||||
import io.anuke.ucore.entities.trait.PosTrait;
|
import io.anuke.ucore.entities.trait.PosTrait;
|
||||||
|
import io.anuke.ucore.entities.trait.VelocityTrait;
|
||||||
|
|
||||||
/**Base interface for targetable entities.*/
|
/**
|
||||||
|
* Base interface for targetable entities.
|
||||||
|
*/
|
||||||
public interface TargetTrait extends PosTrait, VelocityTrait{
|
public interface TargetTrait extends PosTrait, VelocityTrait{
|
||||||
|
|
||||||
boolean isDead();
|
boolean isDead();
|
||||||
|
|
||||||
Team getTeam();
|
Team getTeam();
|
||||||
|
|
||||||
/**Whether this entity is a valid target.*/
|
/**
|
||||||
|
* Whether this entity is a valid target.
|
||||||
|
*/
|
||||||
default boolean isValid(){
|
default boolean isValid(){
|
||||||
return !isDead();
|
return !isDead();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ public interface TypeTrait {
|
|||||||
Array<Supplier<? extends TypeTrait>> registeredTypes = new Array<>();
|
Array<Supplier<? extends TypeTrait>> registeredTypes = new Array<>();
|
||||||
ObjectIntMap<Class<? extends TypeTrait>> typeToID = new ObjectIntMap<>();
|
ObjectIntMap<Class<? extends TypeTrait>> typeToID = new ObjectIntMap<>();
|
||||||
|
|
||||||
/**Register and return a type ID. The supplier should return a fresh instace of that type.*/
|
/**
|
||||||
|
* Register and return a type ID. The supplier should return a fresh instace of that type.
|
||||||
|
*/
|
||||||
static <T extends TypeTrait> void registerType(Class<T> type, Supplier<T> supplier){
|
static <T extends TypeTrait> void registerType(Class<T> type, Supplier<T> supplier){
|
||||||
if(typeToID.get(type, -1) != -1){
|
if(typeToID.get(type, -1) != -1){
|
||||||
throw new RuntimeException("Type is already registered: '" + type + "'!");
|
throw new RuntimeException("Type is already registered: '" + type + "'!");
|
||||||
@@ -21,7 +23,9 @@ public interface TypeTrait {
|
|||||||
lastRegisteredID[0]++;
|
lastRegisteredID[0]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Registers 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()?");
|
||||||
@@ -29,11 +33,14 @@ public interface TypeTrait {
|
|||||||
return registeredTypes.get(id);
|
return registeredTypes.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX.
|
/**
|
||||||
* Do not override!*/
|
* Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX.
|
||||||
|
* Do not override!
|
||||||
|
*/
|
||||||
default int getTypeID(){
|
default int getTypeID(){
|
||||||
int id = typeToID.get(getClass(), -1);
|
int id = typeToID.get(getClass(), -1);
|
||||||
if(id == -1) throw new RuntimeException("Class of type '" + getClass() + "' is not registered! Did you forget to register it in ContentLoader#registerTypes()?");
|
if(id == -1)
|
||||||
|
throw new RuntimeException("Class of type '" + getClass() + "' is not registered! Did you forget to register it in ContentLoader#registerTypes()?");
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,10 @@ import io.anuke.ucore.core.Effects;
|
|||||||
import io.anuke.ucore.core.Timers;
|
import io.anuke.ucore.core.Timers;
|
||||||
import io.anuke.ucore.entities.EntityGroup;
|
import io.anuke.ucore.entities.EntityGroup;
|
||||||
import io.anuke.ucore.graphics.Draw;
|
import io.anuke.ucore.graphics.Draw;
|
||||||
import io.anuke.ucore.util.*;
|
import io.anuke.ucore.util.Angles;
|
||||||
|
import io.anuke.ucore.util.Geometry;
|
||||||
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
import io.anuke.ucore.util.Timer;
|
||||||
|
|
||||||
import java.io.DataInput;
|
import java.io.DataInput;
|
||||||
import java.io.DataOutput;
|
import java.io.DataOutput;
|
||||||
@@ -55,7 +58,37 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
protected Squad squad;
|
protected Squad squad;
|
||||||
protected int spawner;
|
protected int spawner;
|
||||||
|
|
||||||
/**Initialize the type and team of this unit. Only call once!*/
|
/**
|
||||||
|
* internal constructor used for deserialization, DO NOT USE
|
||||||
|
*/
|
||||||
|
public BaseUnit(){
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(called = Loc.server, in = In.entities)
|
||||||
|
public static void onUnitDeath(BaseUnit unit){
|
||||||
|
if(unit == null) return;
|
||||||
|
|
||||||
|
if(Net.server() || !Net.active()){
|
||||||
|
UnitDrops.dropItems(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
float explosiveness = 2f + (unit.inventory.hasItem() ? unit.inventory.getItem().item.explosiveness * unit.inventory.getItem().amount : 0f);
|
||||||
|
float flammability = (unit.inventory.hasItem() ? unit.inventory.getItem().item.flammability * unit.inventory.getItem().amount : 0f);
|
||||||
|
Damage.dynamicExplosion(unit.x, unit.y, flammability, explosiveness, 0f, unit.getSize() / 2f, Palette.darkFlame);
|
||||||
|
|
||||||
|
unit.onSuperDeath();
|
||||||
|
|
||||||
|
ScorchDecal.create(unit.x, unit.y);
|
||||||
|
Effects.effect(ExplosionFx.explosion, unit);
|
||||||
|
Effects.shake(2f, 2f, unit);
|
||||||
|
|
||||||
|
//must run afterwards so the unit's group is not null
|
||||||
|
threads.runDelay(unit::remove);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the type and team of this unit. Only call once!
|
||||||
|
*/
|
||||||
public void init(UnitType type, Team team){
|
public void init(UnitType type, Team team){
|
||||||
if(this.type != null) throw new RuntimeException("This unit is already initialized!");
|
if(this.type != null) throw new RuntimeException("This unit is already initialized!");
|
||||||
|
|
||||||
@@ -63,10 +96,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
this.team = team;
|
this.team = team;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSpawner(Tile tile) {
|
|
||||||
this.spawner = tile.packedPosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
public UnitType getType(){
|
public UnitType getType(){
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@@ -75,10 +104,13 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
return world.tile(spawner);
|
return world.tile(spawner);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**internal constructor used for deserialization, DO NOT USE*/
|
public void setSpawner(Tile tile){
|
||||||
public BaseUnit(){}
|
this.spawner = tile.packedPosition();
|
||||||
|
}
|
||||||
|
|
||||||
/**Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo.*/
|
/**
|
||||||
|
* Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo.
|
||||||
|
*/
|
||||||
public void setWave(){
|
public void setWave(){
|
||||||
isWave = true;
|
isWave = true;
|
||||||
}
|
}
|
||||||
@@ -120,7 +152,9 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Only runs when the unit has a target.*/
|
/**
|
||||||
|
* Only runs when the unit has a target.
|
||||||
|
*/
|
||||||
public void behavior(){
|
public void behavior(){
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -131,6 +165,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
target = null;
|
target = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void targetClosestAllyFlag(BlockFlag flag){
|
public void targetClosestAllyFlag(BlockFlag flag){
|
||||||
Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, flag));
|
Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, flag));
|
||||||
if(target != null) this.target = target.entity;
|
if(target != null) this.target = target.entity;
|
||||||
@@ -395,26 +430,4 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
|||||||
public void onSuperDeath(){
|
public void onSuperDeath(){
|
||||||
super.onDeath();
|
super.onDeath();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(called = Loc.server, in = In.entities)
|
|
||||||
public static void onUnitDeath(BaseUnit unit){
|
|
||||||
if(unit == null) return;
|
|
||||||
|
|
||||||
if(Net.server() || !Net.active()){
|
|
||||||
UnitDrops.dropItems(unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
float explosiveness = 2f + (unit.inventory.hasItem() ? unit.inventory.getItem().item.explosiveness * unit.inventory.getItem().amount : 0f);
|
|
||||||
float flammability = (unit.inventory.hasItem() ? unit.inventory.getItem().item.flammability * unit.inventory.getItem().amount : 0f);
|
|
||||||
Damage.dynamicExplosion(unit.x, unit.y, flammability, explosiveness, 0f, unit.getSize()/2f, Palette.darkFlame);
|
|
||||||
|
|
||||||
unit.onSuperDeath();
|
|
||||||
|
|
||||||
ScorchDecal.create(unit.x, unit.y);
|
|
||||||
Effects.effect(ExplosionFx.explosion, unit);
|
|
||||||
Effects.shake(2f, 2f, unit);
|
|
||||||
|
|
||||||
//must run afterwards so the unit's group is not null
|
|
||||||
threads.runDelay(unit::remove);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,96 @@ import static io.anuke.mindustry.Vars.world;
|
|||||||
public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
|
public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
|
||||||
protected static Translator vec = new Translator();
|
protected static Translator vec = new Translator();
|
||||||
protected static float wobblyness = 0.6f;
|
protected static float wobblyness = 0.6f;
|
||||||
|
public final UnitState
|
||||||
|
|
||||||
|
resupply = new UnitState(){
|
||||||
|
public void entered(){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(){
|
||||||
|
if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){
|
||||||
|
state.set(attack);
|
||||||
|
}else if(!targetHasFlag(BlockFlag.resupplyPoint)){
|
||||||
|
retarget(() -> targetClosestAllyFlag(BlockFlag.resupplyPoint));
|
||||||
|
}else{
|
||||||
|
circle(20f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
idle = new UnitState(){
|
||||||
|
public void update(){
|
||||||
|
retarget(() -> {
|
||||||
|
targetClosest();
|
||||||
|
targetClosestEnemyFlag(BlockFlag.target);
|
||||||
|
|
||||||
|
if(target != null){
|
||||||
|
setState(attack);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
target = getClosestCore();
|
||||||
|
if(target != null){
|
||||||
|
circle(50f);
|
||||||
|
}
|
||||||
|
velocity.scl(0.8f);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
attack = new UnitState(){
|
||||||
|
public void entered(){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(){
|
||||||
|
if(Units.invalidateTarget(target, team, x, y)){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!inventory.hasAmmo()){
|
||||||
|
state.set(resupply);
|
||||||
|
}else if(target == null){
|
||||||
|
retarget(() -> {
|
||||||
|
targetClosest();
|
||||||
|
targetClosestEnemyFlag(BlockFlag.target);
|
||||||
|
targetClosestEnemyFlag(BlockFlag.producer);
|
||||||
|
|
||||||
|
if(target == null){
|
||||||
|
setState(idle);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
attack(150f);
|
||||||
|
|
||||||
|
if((Mathf.angNear(angleTo(target), rotation, 15f) || !inventory.getAmmo().bullet.keepVelocity) //bombers don't care about rotation
|
||||||
|
&& distanceTo(target) < inventory.getAmmo().getRange()){
|
||||||
|
AmmoType ammo = inventory.getAmmo();
|
||||||
|
inventory.useAmmo();
|
||||||
|
|
||||||
|
Vector2 to = Predict.intercept(FlyingUnit.this, target, ammo.bullet.speed);
|
||||||
|
|
||||||
|
getWeapon().update(FlyingUnit.this, to.x, to.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
retreat = new UnitState(){
|
||||||
|
public void entered(){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(){
|
||||||
|
if(health >= maxHealth()){
|
||||||
|
state.set(attack);
|
||||||
|
}else if(!targetHasFlag(BlockFlag.repair)){
|
||||||
|
retarget(() -> {
|
||||||
|
Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair));
|
||||||
|
if(target != null) FlyingUnit.this.target = target.entity;
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
circle(20f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
protected Trail trail = new Trail(8);
|
protected Trail trail = new Trail(8);
|
||||||
protected CarriableTrait carrying;
|
protected CarriableTrait carrying;
|
||||||
|
|
||||||
@@ -164,95 +253,4 @@ public abstract class FlyingUnit extends BaseUnit implements CarryTrait{
|
|||||||
|
|
||||||
velocity.add(vec);
|
velocity.add(vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final UnitState
|
|
||||||
|
|
||||||
resupply = new UnitState(){
|
|
||||||
public void entered() {
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update() {
|
|
||||||
if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){
|
|
||||||
state.set(attack);
|
|
||||||
}else if(!targetHasFlag(BlockFlag.resupplyPoint)){
|
|
||||||
retarget(() -> targetClosestAllyFlag(BlockFlag.resupplyPoint));
|
|
||||||
}else{
|
|
||||||
circle(20f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
idle = new UnitState() {
|
|
||||||
public void update() {
|
|
||||||
retarget(() -> {
|
|
||||||
targetClosest();
|
|
||||||
targetClosestEnemyFlag(BlockFlag.target);
|
|
||||||
|
|
||||||
if(target != null){
|
|
||||||
setState(attack);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
target = getClosestCore();
|
|
||||||
if(target != null){
|
|
||||||
circle(50f);
|
|
||||||
}
|
|
||||||
velocity.scl(0.8f);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
attack = new UnitState(){
|
|
||||||
public void entered() {
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update() {
|
|
||||||
if(Units.invalidateTarget(target, team, x, y)){
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!inventory.hasAmmo()) {
|
|
||||||
state.set(resupply);
|
|
||||||
}else if (target == null){
|
|
||||||
retarget(() -> {
|
|
||||||
targetClosest();
|
|
||||||
targetClosestEnemyFlag(BlockFlag.target);
|
|
||||||
targetClosestEnemyFlag(BlockFlag.producer);
|
|
||||||
|
|
||||||
if(target == null){
|
|
||||||
setState(idle);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}else{
|
|
||||||
attack(150f);
|
|
||||||
|
|
||||||
if ((Mathf.angNear(angleTo(target), rotation, 15f) || !inventory.getAmmo().bullet.keepVelocity) //bombers don't care about rotation
|
|
||||||
&& distanceTo(target) < inventory.getAmmo().getRange()) {
|
|
||||||
AmmoType ammo = inventory.getAmmo();
|
|
||||||
inventory.useAmmo();
|
|
||||||
|
|
||||||
Vector2 to = Predict.intercept(FlyingUnit.this, target, ammo.bullet.speed);
|
|
||||||
|
|
||||||
getWeapon().update(FlyingUnit.this, to.x, to.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
retreat = new UnitState() {
|
|
||||||
public void entered() {
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update() {
|
|
||||||
if(health >= maxHealth()){
|
|
||||||
state.set(attack);
|
|
||||||
}else if(!targetHasFlag(BlockFlag.repair)){
|
|
||||||
retarget(() -> {
|
|
||||||
Tile target = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair));
|
|
||||||
if (target != null) FlyingUnit.this.target = target.entity;
|
|
||||||
});
|
|
||||||
}else{
|
|
||||||
circle(20f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,83 @@ public abstract class GroundUnit extends BaseUnit {
|
|||||||
|
|
||||||
protected float walkTime;
|
protected float walkTime;
|
||||||
protected float baseRotation;
|
protected float baseRotation;
|
||||||
|
public final UnitState
|
||||||
|
|
||||||
|
resupply = new UnitState(){
|
||||||
|
public void entered(){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(){
|
||||||
|
Tile tile = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.resupplyPoint));
|
||||||
|
|
||||||
|
if(tile != null && distanceTo(tile) > 40){
|
||||||
|
moveAwayFromCore();
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO move toward resupply point
|
||||||
|
if(isWave || inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){
|
||||||
|
state.set(attack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
attack = new UnitState(){
|
||||||
|
public void entered(){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(){
|
||||||
|
TileEntity core = getClosestEnemyCore();
|
||||||
|
float dst = core == null ? 0 : distanceTo(core);
|
||||||
|
|
||||||
|
if(core != null && inventory.hasAmmo() && dst < inventory.getAmmo().getRange() / 1.1f){
|
||||||
|
target = core;
|
||||||
|
}else{
|
||||||
|
retarget(() -> targetClosest());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!inventory.hasAmmo()){
|
||||||
|
state.set(resupply);
|
||||||
|
}else if(target != null){
|
||||||
|
if(core != null){
|
||||||
|
if(dst > inventory.getAmmo().getRange() * 0.5f){
|
||||||
|
moveToCore();
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
moveToCore();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(distanceTo(target) < inventory.getAmmo().getRange()){
|
||||||
|
rotate(angleTo(target));
|
||||||
|
|
||||||
|
if(Mathf.angNear(angleTo(target), rotation, 13f)){
|
||||||
|
AmmoType ammo = inventory.getAmmo();
|
||||||
|
|
||||||
|
Vector2 to = Predict.intercept(GroundUnit.this, target, ammo.bullet.speed);
|
||||||
|
|
||||||
|
getWeapon().update(GroundUnit.this, to.x, to.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
moveToCore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
retreat = new UnitState(){
|
||||||
|
public void entered(){
|
||||||
|
target = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(){
|
||||||
|
if(health >= health){
|
||||||
|
state.set(attack);
|
||||||
|
}
|
||||||
|
|
||||||
|
moveAwayFromCore();
|
||||||
|
}
|
||||||
|
};
|
||||||
protected Weapon weapon;
|
protected Weapon weapon;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -75,6 +152,10 @@ public abstract class GroundUnit extends BaseUnit {
|
|||||||
return weapon;
|
return weapon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setWeapon(Weapon weapon){
|
||||||
|
this.weapon = weapon;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void draw(){
|
public void draw(){
|
||||||
Draw.alpha(hitTime / hitDuration);
|
Draw.alpha(hitTime / hitDuration);
|
||||||
@@ -159,10 +240,6 @@ public abstract class GroundUnit extends BaseUnit {
|
|||||||
super.readSave(stream);
|
super.readSave(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWeapon(Weapon weapon){
|
|
||||||
this.weapon = weapon;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void moveToCore(){
|
protected void moveToCore(){
|
||||||
Tile tile = world.tileWorld(x, y);
|
Tile tile = world.tileWorld(x, y);
|
||||||
if(tile == null) return;
|
if(tile == null) return;
|
||||||
@@ -189,82 +266,4 @@ public abstract class GroundUnit extends BaseUnit {
|
|||||||
walkTime += Timers.delta();
|
walkTime += Timers.delta();
|
||||||
velocity.add(vec);
|
velocity.add(vec);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final UnitState
|
|
||||||
|
|
||||||
resupply = new UnitState(){
|
|
||||||
public void entered() {
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update() {
|
|
||||||
Tile tile = Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.resupplyPoint));
|
|
||||||
|
|
||||||
if (tile != null && distanceTo(tile) > 40) {
|
|
||||||
moveAwayFromCore();
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO move toward resupply point
|
|
||||||
if(isWave || inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){
|
|
||||||
state.set(attack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
attack = new UnitState(){
|
|
||||||
public void entered() {
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update() {
|
|
||||||
TileEntity core = getClosestEnemyCore();
|
|
||||||
float dst = core == null ? 0 :distanceTo(core);
|
|
||||||
|
|
||||||
if(core != null && inventory.hasAmmo() && dst < inventory.getAmmo().getRange()/1.1f){
|
|
||||||
target = core;
|
|
||||||
}else {
|
|
||||||
retarget(() -> targetClosest());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!inventory.hasAmmo()) {
|
|
||||||
state.set(resupply);
|
|
||||||
}else if(target != null){
|
|
||||||
if(core != null){
|
|
||||||
if(dst > inventory.getAmmo().getRange() * 0.5f){
|
|
||||||
moveToCore();
|
|
||||||
}
|
|
||||||
|
|
||||||
}else{
|
|
||||||
moveToCore();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(distanceTo(target) < inventory.getAmmo().getRange()){
|
|
||||||
rotate(angleTo(target));
|
|
||||||
|
|
||||||
if (Mathf.angNear(angleTo(target), rotation, 13f)) {
|
|
||||||
AmmoType ammo = inventory.getAmmo();
|
|
||||||
|
|
||||||
Vector2 to = Predict.intercept(GroundUnit.this, target, ammo.bullet.speed);
|
|
||||||
|
|
||||||
getWeapon().update(GroundUnit.this, to.x, to.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}else{
|
|
||||||
moveToCore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
retreat = new UnitState() {
|
|
||||||
public void entered() {
|
|
||||||
target = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update() {
|
|
||||||
if(health >= health){
|
|
||||||
state.set(attack);
|
|
||||||
}
|
|
||||||
|
|
||||||
moveAwayFromCore();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,10 @@ import io.anuke.ucore.util.Translator;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.threads;
|
import static io.anuke.mindustry.Vars.threads;
|
||||||
|
|
||||||
/**Used to group entities together, for formations and such.
|
/**
|
||||||
* Usually, squads are used by units spawned in the same wave.*/
|
* Used to group entities together, for formations and such.
|
||||||
|
* Usually, squads are used by units spawned in the same wave.
|
||||||
|
*/
|
||||||
public class Squad{
|
public class Squad{
|
||||||
public Vector2 direction = new Translator();
|
public Vector2 direction = new Translator();
|
||||||
public int units;
|
public int units;
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
package io.anuke.mindustry.entities.units;
|
package io.anuke.mindustry.entities.units;
|
||||||
|
|
||||||
public interface UnitState{
|
public interface UnitState{
|
||||||
default void entered(){}
|
default void entered(){
|
||||||
default void exited(){}
|
}
|
||||||
default void update(){}
|
|
||||||
|
default void exited(){
|
||||||
|
}
|
||||||
|
|
||||||
|
default void update(){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,12 +18,9 @@ import io.anuke.ucore.util.Bundles;
|
|||||||
public class UnitType implements UnlockableContent{
|
public class UnitType implements UnlockableContent{
|
||||||
private static byte lastid = 0;
|
private static byte lastid = 0;
|
||||||
private static Array<UnitType> types = new Array<>();
|
private static Array<UnitType> types = new Array<>();
|
||||||
|
|
||||||
protected final Supplier<? extends BaseUnit> constructor;
|
|
||||||
|
|
||||||
public final String name;
|
public final String name;
|
||||||
public final byte id;
|
public final byte id;
|
||||||
|
protected final Supplier<? extends BaseUnit> constructor;
|
||||||
public float health = 60;
|
public float health = 60;
|
||||||
public float hitsize = 5f;
|
public float hitsize = 5f;
|
||||||
public float hitsizeTile = 4f;
|
public float hitsizeTile = 4f;
|
||||||
@@ -57,6 +54,14 @@ public class UnitType implements UnlockableContent{
|
|||||||
TypeTrait.registerType(type, mainConstructor);
|
TypeTrait.registerType(type, mainConstructor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static UnitType getByID(byte id){
|
||||||
|
return types.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Array<UnitType> all(){
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void displayInfo(Table table){
|
public void displayInfo(Table table){
|
||||||
ContentDisplay.displayUnit(table, this);
|
ContentDisplay.displayUnit(table, this);
|
||||||
@@ -103,12 +108,4 @@ public class UnitType implements UnlockableContent{
|
|||||||
unit.init(this, team);
|
unit.init(this, team);
|
||||||
return unit;
|
return unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UnitType getByID(byte id){
|
|
||||||
return types.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Array<UnitType> all(){
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,184 +47,6 @@ public class Drone extends FlyingUnit implements BuilderTrait {
|
|||||||
protected Item targetItem;
|
protected Item targetItem;
|
||||||
protected Tile mineTile;
|
protected Tile mineTile;
|
||||||
protected Queue<BuildRequest> placeQueue = new ThreadQueue<>();
|
protected Queue<BuildRequest> placeQueue = new ThreadQueue<>();
|
||||||
|
|
||||||
/**Initialize placement event notifier system.
|
|
||||||
* Static initialization is to be avoided, thus, this is done lazily.*/
|
|
||||||
private static void initEvents(){
|
|
||||||
if(initialized) return;
|
|
||||||
|
|
||||||
toMine = ObjectSet.with(Items.lead, Items.tungsten);
|
|
||||||
|
|
||||||
Events.on(BlockBuildEvent.class, (team, tile) -> {
|
|
||||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
|
||||||
|
|
||||||
if(!(tile.entity instanceof BuildEntity)) return;
|
|
||||||
BuildEntity entity = tile.entity();
|
|
||||||
|
|
||||||
for(BaseUnit unit : group.all()){
|
|
||||||
if(unit instanceof Drone){
|
|
||||||
((Drone) unit).notifyPlaced(entity);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
initEvents();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void notifyPlaced(BuildEntity entity){
|
|
||||||
float timeToBuild = entity.recipe.cost;
|
|
||||||
float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0);
|
|
||||||
|
|
||||||
if(dist / type.maxVelocity < timeToBuild * 0.9f){
|
|
||||||
//CallEntity.onDroneBeginBuild(this, entity.tile, entity.recipe);
|
|
||||||
target = entity;
|
|
||||||
setState(build);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getBuildPower(Tile tile) {
|
|
||||||
return type.buildPower;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getMinePower() {
|
|
||||||
return type.minePower;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Queue<BuildRequest> getPlaceQueue() {
|
|
||||||
return placeQueue;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Tile getMineTile() {
|
|
||||||
return mineTile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setMineTile(Tile tile) {
|
|
||||||
mineTile = tile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void update() {
|
|
||||||
super.update();
|
|
||||||
|
|
||||||
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f);
|
|
||||||
y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f);
|
|
||||||
|
|
||||||
updateBuilding(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void updateRotation() {
|
|
||||||
if(target != null && (state.is(repair) || state.is(mine))){
|
|
||||||
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.3f);
|
|
||||||
}else{
|
|
||||||
rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(velocity.len() <= 0.2f && !(state.is(repair) && target != null)){
|
|
||||||
rotation += Mathf.sin(Timers.time() + id * 99, 10f, 5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void behavior() {
|
|
||||||
if(health <= health * type.retreatPercent &&
|
|
||||||
Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){
|
|
||||||
setState(retreat);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UnitState getStartState() {
|
|
||||||
return repair;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void drawOver() {
|
|
||||||
trail.draw(Palette.lightTrail, 3f);
|
|
||||||
|
|
||||||
TargetTrait entity = target;
|
|
||||||
|
|
||||||
if(entity instanceof TileEntity && state.is(repair)){
|
|
||||||
float len = 5f;
|
|
||||||
Draw.color(Color.BLACK, Color.WHITE, 0.95f + Mathf.absin(Timers.time(), 0.8f, 0.05f));
|
|
||||||
Shapes.laser("beam", "beam-end",
|
|
||||||
x + Angles.trnsx(rotation, len),
|
|
||||||
y + Angles.trnsy(rotation, len),
|
|
||||||
entity.getX(), entity.getY());
|
|
||||||
Draw.color();
|
|
||||||
}
|
|
||||||
|
|
||||||
drawBuilding(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float drawSize() {
|
|
||||||
return isBuilding() ? placeDistance*2f : 30f;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public float getAmmoFraction() {
|
|
||||||
return inventory.getItem().amount / (float)type.itemCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void findItem(){
|
|
||||||
TileEntity entity = getClosestCore();
|
|
||||||
if(entity == null){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
targetItem = Mathf.findMin(toMine, (a, b) -> -Integer.compare(entity.items.get(a), entity.items.get(b)));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean findItemDrop(){
|
|
||||||
TileEntity core = getClosestCore();
|
|
||||||
|
|
||||||
if(core == null) return false;
|
|
||||||
|
|
||||||
//find nearby dropped items to pick up if applicable
|
|
||||||
ItemDrop drop = EntityPhysics.getClosest(itemGroup, x, y, 60f,
|
|
||||||
item -> core.tile.block().acceptStack(item.getItem(), item.getAmount(), core.tile, Drone.this) == item.getAmount() &&
|
|
||||||
inventory.canAcceptItem(item.getItem(), 1));
|
|
||||||
if(drop != null){
|
|
||||||
setState(pickup);
|
|
||||||
target = drop;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean canCreateBlocks() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(DataOutput data) throws IOException {
|
|
||||||
super.write(data);
|
|
||||||
data.writeInt(mineTile == null ? -1 : mineTile.packedPosition());
|
|
||||||
writeBuilding(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void read(DataInput data, long time) throws IOException {
|
|
||||||
super.read(data, time);
|
|
||||||
int mined = data.readInt();
|
|
||||||
|
|
||||||
readBuilding(data);
|
|
||||||
|
|
||||||
if(mined != -1){
|
|
||||||
mineTile = world.tile(mined);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final UnitState
|
public final UnitState
|
||||||
|
|
||||||
build = new UnitState(){
|
build = new UnitState(){
|
||||||
@@ -432,4 +254,183 @@ public class Drone extends FlyingUnit implements BuilderTrait {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
initEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize placement event notifier system.
|
||||||
|
* Static initialization is to be avoided, thus, this is done lazily.
|
||||||
|
*/
|
||||||
|
private static void initEvents(){
|
||||||
|
if(initialized) return;
|
||||||
|
|
||||||
|
toMine = ObjectSet.with(Items.lead, Items.tungsten);
|
||||||
|
|
||||||
|
Events.on(BlockBuildEvent.class, (team, tile) -> {
|
||||||
|
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||||
|
|
||||||
|
if(!(tile.entity instanceof BuildEntity)) return;
|
||||||
|
BuildEntity entity = tile.entity();
|
||||||
|
|
||||||
|
for(BaseUnit unit : group.all()){
|
||||||
|
if(unit instanceof Drone){
|
||||||
|
((Drone) unit).notifyPlaced(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyPlaced(BuildEntity entity){
|
||||||
|
float timeToBuild = entity.recipe.cost;
|
||||||
|
float dist = Math.min(entity.distanceTo(x, y) - placeDistance, 0);
|
||||||
|
|
||||||
|
if(dist / type.maxVelocity < timeToBuild * 0.9f){
|
||||||
|
//CallEntity.onDroneBeginBuild(this, entity.tile, entity.recipe);
|
||||||
|
target = entity;
|
||||||
|
setState(build);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getBuildPower(Tile tile){
|
||||||
|
return type.buildPower;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getMinePower(){
|
||||||
|
return type.minePower;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Queue<BuildRequest> getPlaceQueue(){
|
||||||
|
return placeQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Tile getMineTile(){
|
||||||
|
return mineTile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMineTile(Tile tile){
|
||||||
|
mineTile = tile;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(){
|
||||||
|
super.update();
|
||||||
|
|
||||||
|
x += Mathf.sin(Timers.time() + id * 999, 25f, 0.07f);
|
||||||
|
y += Mathf.cos(Timers.time() + id * 999, 25f, 0.07f);
|
||||||
|
|
||||||
|
updateBuilding(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void updateRotation(){
|
||||||
|
if(target != null && (state.is(repair) || state.is(mine))){
|
||||||
|
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.3f);
|
||||||
|
}else{
|
||||||
|
rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(velocity.len() <= 0.2f && !(state.is(repair) && target != null)){
|
||||||
|
rotation += Mathf.sin(Timers.time() + id * 99, 10f, 5f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void behavior(){
|
||||||
|
if(health <= health * type.retreatPercent &&
|
||||||
|
Geometry.findClosest(x, y, world.indexer().getAllied(team, BlockFlag.repair)) != null){
|
||||||
|
setState(retreat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UnitState getStartState(){
|
||||||
|
return repair;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void drawOver(){
|
||||||
|
trail.draw(Palette.lightTrail, 3f);
|
||||||
|
|
||||||
|
TargetTrait entity = target;
|
||||||
|
|
||||||
|
if(entity instanceof TileEntity && state.is(repair)){
|
||||||
|
float len = 5f;
|
||||||
|
Draw.color(Color.BLACK, Color.WHITE, 0.95f + Mathf.absin(Timers.time(), 0.8f, 0.05f));
|
||||||
|
Shapes.laser("beam", "beam-end",
|
||||||
|
x + Angles.trnsx(rotation, len),
|
||||||
|
y + Angles.trnsy(rotation, len),
|
||||||
|
entity.getX(), entity.getY());
|
||||||
|
Draw.color();
|
||||||
|
}
|
||||||
|
|
||||||
|
drawBuilding(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float drawSize(){
|
||||||
|
return isBuilding() ? placeDistance * 2f : 30f;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getAmmoFraction(){
|
||||||
|
return inventory.getItem().amount / (float) type.itemCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void findItem(){
|
||||||
|
TileEntity entity = getClosestCore();
|
||||||
|
if(entity == null){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
targetItem = Mathf.findMin(toMine, (a, b) -> -Integer.compare(entity.items.get(a), entity.items.get(b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean findItemDrop(){
|
||||||
|
TileEntity core = getClosestCore();
|
||||||
|
|
||||||
|
if(core == null) return false;
|
||||||
|
|
||||||
|
//find nearby dropped items to pick up if applicable
|
||||||
|
ItemDrop drop = EntityPhysics.getClosest(itemGroup, x, y, 60f,
|
||||||
|
item -> core.tile.block().acceptStack(item.getItem(), item.getAmount(), core.tile, Drone.this) == item.getAmount() &&
|
||||||
|
inventory.canAcceptItem(item.getItem(), 1));
|
||||||
|
if(drop != null){
|
||||||
|
setState(pickup);
|
||||||
|
target = drop;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCreateBlocks(){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(DataOutput data) throws IOException{
|
||||||
|
super.write(data);
|
||||||
|
data.writeInt(mineTile == null ? -1 : mineTile.packedPosition());
|
||||||
|
writeBuilding(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void read(DataInput data, long time) throws IOException{
|
||||||
|
super.read(data, time);
|
||||||
|
int mined = data.readInt();
|
||||||
|
|
||||||
|
readBuilding(data);
|
||||||
|
|
||||||
|
if(mined != -1){
|
||||||
|
mineTile = world.tile(mined);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,32 @@ package io.anuke.mindustry.game;
|
|||||||
|
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
/**Base interface for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}.*/
|
/**
|
||||||
|
* Base interface for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}.
|
||||||
|
*/
|
||||||
public interface Content{
|
public interface Content{
|
||||||
|
|
||||||
/**Returns the type name of this piece of content.
|
/**
|
||||||
* This should return the same value for all instances of this content type.*/
|
* Returns the type name of this piece of content.
|
||||||
|
* This should return the same value for all instances of this content type.
|
||||||
|
*/
|
||||||
String getContentTypeName();
|
String getContentTypeName();
|
||||||
|
|
||||||
/**Returns a list of all instances of this content.*/
|
/**
|
||||||
|
* Returns a list of all instances of this content.
|
||||||
|
*/
|
||||||
Array<? extends Content> getAll();
|
Array<? extends Content> getAll();
|
||||||
|
|
||||||
/**Called after all content is created. Do not use to load regions or texture data!*/
|
/**
|
||||||
default void init(){}
|
* Called after all content is created. Do not use to load regions or texture data!
|
||||||
|
*/
|
||||||
|
default void init(){
|
||||||
|
}
|
||||||
|
|
||||||
/**Called after all content is created, only on non-headless versions.
|
/**
|
||||||
* Use for loading regions or other image data.*/
|
* Called after all content is created, only on non-headless versions.
|
||||||
default void load(){}
|
* Use for loading regions or other image data.
|
||||||
|
*/
|
||||||
|
default void load(){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,18 @@ import io.anuke.ucore.core.Events;
|
|||||||
import io.anuke.ucore.core.Settings;
|
import io.anuke.ucore.core.Settings;
|
||||||
|
|
||||||
public class ContentDatabase{
|
public class ContentDatabase{
|
||||||
/**Maps unlockable type names to a set of unlocked content.*/
|
/**
|
||||||
|
* Maps unlockable type names to a set of unlocked content.
|
||||||
|
*/
|
||||||
private ObjectMap<String, ObjectSet<String>> unlocked = new ObjectMap<>();
|
private ObjectMap<String, ObjectSet<String>> unlocked = new ObjectMap<>();
|
||||||
/**Whether unlockables have changed since the last save.*/
|
/**
|
||||||
|
* Whether unlockables have changed since the last save.
|
||||||
|
*/
|
||||||
private boolean dirty;
|
private boolean dirty;
|
||||||
|
|
||||||
/**Returns whether or not this piece of content is unlocked yet.*/
|
/**
|
||||||
|
* Returns whether or not this piece of content is unlocked yet.
|
||||||
|
*/
|
||||||
public boolean isUnlocked(UnlockableContent content){
|
public boolean isUnlocked(UnlockableContent content){
|
||||||
if(!unlocked.containsKey(content.getContentTypeName())){
|
if(!unlocked.containsKey(content.getContentTypeName())){
|
||||||
unlocked.put(content.getContentTypeName(), new ObjectSet<>());
|
unlocked.put(content.getContentTypeName(), new ObjectSet<>());
|
||||||
@@ -25,10 +31,13 @@ public class ContentDatabase {
|
|||||||
return set.contains(content.getContentName());
|
return set.contains(content.getContentName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Makes this piece of content 'unlocked', if possible.
|
/**
|
||||||
|
* Makes this piece of content 'unlocked', if possible.
|
||||||
* If this piece of content is already unlocked or cannot be unlocked due to dependencies, nothing changes.
|
* If this piece of content is already unlocked or cannot be unlocked due to dependencies, nothing changes.
|
||||||
* Results are not saved until you call {@link #save()}.
|
* Results are not saved until you call {@link #save()}.
|
||||||
* @return whether or not this content was newly unlocked.*/
|
*
|
||||||
|
* @return whether or not this content was newly unlocked.
|
||||||
|
*/
|
||||||
public boolean unlockContent(UnlockableContent content){
|
public boolean unlockContent(UnlockableContent content){
|
||||||
if(!content.canBeUnlocked()) return false;
|
if(!content.canBeUnlocked()) return false;
|
||||||
|
|
||||||
@@ -48,12 +57,16 @@ public class ContentDatabase {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether unlockables have changed since the last save.*/
|
/**
|
||||||
|
* Returns whether unlockables have changed since the last save.
|
||||||
|
*/
|
||||||
public boolean isDirty(){
|
public boolean isDirty(){
|
||||||
return dirty;
|
return dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Clears all unlocked content.*/
|
/**
|
||||||
|
* Clears all unlocked content.
|
||||||
|
*/
|
||||||
public void reset(){
|
public void reset(){
|
||||||
unlocked.clear();
|
unlocked.clear();
|
||||||
dirty = true;
|
dirty = true;
|
||||||
|
|||||||
@@ -10,13 +10,19 @@ public enum Difficulty {
|
|||||||
//purge removed due to new wave system
|
//purge removed due to new wave system
|
||||||
/*purge(0.25f, 0.01f, 0.25f)*/;
|
/*purge(0.25f, 0.01f, 0.25f)*/;
|
||||||
|
|
||||||
/**The scaling of how many waves it takes for one more enemy of a type to appear.
|
/**
|
||||||
|
* The scaling of how many waves it takes for one more enemy of a type to appear.
|
||||||
* For example: with enemeyScaling = 2 and the default scaling being 2, it would take 4 waves for
|
* For example: with enemeyScaling = 2 and the default scaling being 2, it would take 4 waves for
|
||||||
* an enemy spawn to go from 1->2 enemies.*/
|
* an enemy spawn to go from 1->2 enemies.
|
||||||
|
*/
|
||||||
public final float enemyScaling;
|
public final float enemyScaling;
|
||||||
/**Multiplier of the time between waves.*/
|
/**
|
||||||
|
* Multiplier of the time between waves.
|
||||||
|
*/
|
||||||
public final float timeScaling;
|
public final float timeScaling;
|
||||||
/**Scaling of max time between waves. Default time is 4 minutes.*/
|
/**
|
||||||
|
* Scaling of max time between waves. Default time is 4 minutes.
|
||||||
|
*/
|
||||||
public final float maxTimeScaling;
|
public final float maxTimeScaling;
|
||||||
|
|
||||||
private String value;
|
private String value;
|
||||||
|
|||||||
@@ -22,19 +22,25 @@ public class EventType {
|
|||||||
void handle();
|
void handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**This event is called from the logic thread.
|
/**
|
||||||
* DO NOT INITIALIZE GRAPHICS HERE.*/
|
* This event is called from the logic thread.
|
||||||
|
* DO NOT INITIALIZE GRAPHICS HERE.
|
||||||
|
*/
|
||||||
public interface WorldLoadEvent extends Event{
|
public interface WorldLoadEvent extends Event{
|
||||||
void handle();
|
void handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Called after the WorldLoadEvent is, and all logic has been loaded.
|
/**
|
||||||
* It is safe to intialize graphics here.*/
|
* Called after the WorldLoadEvent is, and all logic has been loaded.
|
||||||
|
* It is safe to intialize graphics here.
|
||||||
|
*/
|
||||||
public interface WorldLoadGraphicsEvent extends Event{
|
public interface WorldLoadGraphicsEvent extends Event{
|
||||||
void handle();
|
void handle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Called from the logic thread. Do not access graphics here!*/
|
/**
|
||||||
|
* Called from the logic thread. Do not access graphics here!
|
||||||
|
*/
|
||||||
public interface TileChangeEvent extends Event{
|
public interface TileChangeEvent extends Event{
|
||||||
void handle(Tile tile);
|
void handle(Tile tile);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,42 +8,72 @@ import io.anuke.mindustry.type.ItemStack;
|
|||||||
import io.anuke.mindustry.type.StatusEffect;
|
import io.anuke.mindustry.type.StatusEffect;
|
||||||
import io.anuke.mindustry.type.Weapon;
|
import io.anuke.mindustry.type.Weapon;
|
||||||
|
|
||||||
/**A spawn group defines spawn information for a specific type of unit, with optional extra information like
|
/**
|
||||||
|
* A spawn group defines spawn information for a specific type of unit, with optional extra information like
|
||||||
* weapon equipped, ammo used, and status effects.
|
* weapon equipped, ammo used, and status effects.
|
||||||
* Each spawn group can have multiple sub-groups spawned in different areas of the map.*/
|
* Each spawn group can have multiple sub-groups spawned in different areas of the map.
|
||||||
|
*/
|
||||||
public class SpawnGroup{
|
public class SpawnGroup{
|
||||||
/**The unit type spawned*/
|
/**
|
||||||
|
* The unit type spawned
|
||||||
|
*/
|
||||||
public final UnitType type;
|
public final UnitType type;
|
||||||
/**When this spawn should end*/
|
/**
|
||||||
|
* When this spawn should end
|
||||||
|
*/
|
||||||
protected int end = Integer.MAX_VALUE;
|
protected int end = Integer.MAX_VALUE;
|
||||||
/**When this spawn should start*/
|
/**
|
||||||
|
* When this spawn should start
|
||||||
|
*/
|
||||||
protected int begin;
|
protected int begin;
|
||||||
/**The spacing, in waves, of spawns. For example, 2 = spawns every other wave*/
|
/**
|
||||||
|
* The spacing, in waves, of spawns. For example, 2 = spawns every other wave
|
||||||
|
*/
|
||||||
protected int spacing = 1;
|
protected int spacing = 1;
|
||||||
/**Maximum amount of units that spawn*/
|
/**
|
||||||
|
* Maximum amount of units that spawn
|
||||||
|
*/
|
||||||
protected int max = 60;
|
protected int max = 60;
|
||||||
/**How many waves need to pass before the amount of units spawned increases by 1*/
|
/**
|
||||||
|
* How many waves need to pass before the amount of units spawned increases by 1
|
||||||
|
*/
|
||||||
protected float unitScaling = 9999f;
|
protected float unitScaling = 9999f;
|
||||||
/**How many waves need to pass before the amount of instances of this group increases by 1*/
|
/**
|
||||||
|
* How many waves need to pass before the amount of instances of this group increases by 1
|
||||||
|
*/
|
||||||
protected float groupScaling = 9999f;
|
protected float groupScaling = 9999f;
|
||||||
/**Amount of enemies spawned initially, with no scaling*/
|
/**
|
||||||
|
* Amount of enemies spawned initially, with no scaling
|
||||||
|
*/
|
||||||
protected int unitAmount = 1;
|
protected int unitAmount = 1;
|
||||||
/**Amount of enemies spawned initially, with no scaling*/
|
/**
|
||||||
|
* Amount of enemies spawned initially, with no scaling
|
||||||
|
*/
|
||||||
protected int groupAmount = 1;
|
protected int groupAmount = 1;
|
||||||
/**Weapon used by the spawned unit. Null to disable. Only applicable to ground units.*/
|
/**
|
||||||
|
* Weapon used by the spawned unit. Null to disable. Only applicable to ground units.
|
||||||
|
*/
|
||||||
protected Weapon weapon;
|
protected Weapon weapon;
|
||||||
/**Status effect applied to the spawned unit. Null to disable.*/
|
/**
|
||||||
|
* Status effect applied to the spawned unit. Null to disable.
|
||||||
|
*/
|
||||||
protected StatusEffect effect;
|
protected StatusEffect effect;
|
||||||
/**Items this unit spawns with. Null to disable.*/
|
/**
|
||||||
|
* Items this unit spawns with. Null to disable.
|
||||||
|
*/
|
||||||
protected ItemStack items;
|
protected ItemStack items;
|
||||||
/**Ammo type this unit spawns with. Null to use the first available ammo.*/
|
/**
|
||||||
|
* Ammo type this unit spawns with. Null to use the first available ammo.
|
||||||
|
*/
|
||||||
protected Item ammoItem;
|
protected Item ammoItem;
|
||||||
|
|
||||||
public SpawnGroup(UnitType type){
|
public SpawnGroup(UnitType type){
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the amount of units spawned on a specific wave.*/
|
/**
|
||||||
|
* Returns the amount of units spawned on a specific wave.
|
||||||
|
*/
|
||||||
public int getUnitsSpawned(int wave){
|
public int getUnitsSpawned(int wave){
|
||||||
if(wave < begin || wave > end || (wave - begin) % spacing != 0){
|
if(wave < begin || wave > end || (wave - begin) % spacing != 0){
|
||||||
return 0;
|
return 0;
|
||||||
@@ -53,7 +83,9 @@ public class SpawnGroup {
|
|||||||
return Math.min(unitAmount - 1 + Math.max((int) ((wave / spacing) / scaling), 1), max);
|
return Math.min(unitAmount - 1 + Math.max((int) ((wave / spacing) / scaling), 1), max);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the amount of different unit groups at a specific wave.*/
|
/**
|
||||||
|
* Returns the amount of different unit groups at a specific wave.
|
||||||
|
*/
|
||||||
public int getGroupsSpawned(int wave){
|
public int getGroupsSpawned(int wave){
|
||||||
if(wave < begin || wave > end || (wave - begin) % spacing != 0){
|
if(wave < begin || wave > end || (wave - begin) % spacing != 0){
|
||||||
return 0;
|
return 0;
|
||||||
@@ -63,8 +95,10 @@ public class SpawnGroup {
|
|||||||
return Math.min(groupAmount - 1 + Math.max((int) ((wave / spacing) / groupScaling), 1), max);
|
return Math.min(groupAmount - 1 + Math.max((int) ((wave / spacing) / groupScaling), 1), max);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Creates a unit, and assigns correct values based on this group's data.
|
/**
|
||||||
* This method does not add() the unit.*/
|
* Creates a unit, and assigns correct values based on this group's data.
|
||||||
|
* This method does not add() the unit.
|
||||||
|
*/
|
||||||
public BaseUnit createUnit(Team team){
|
public BaseUnit createUnit(Team team){
|
||||||
BaseUnit unit = type.create(team);
|
BaseUnit unit = type.create(team);
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,10 @@ public enum Team {
|
|||||||
purple(Color.valueOf("ba5bd9")),
|
purple(Color.valueOf("ba5bd9")),
|
||||||
orange(Color.valueOf("e8c66a"));
|
orange(Color.valueOf("e8c66a"));
|
||||||
|
|
||||||
|
public final static Team[] all = values();
|
||||||
public final Color color;
|
public final Color color;
|
||||||
public final int intColor;
|
public final int intColor;
|
||||||
|
|
||||||
public final static Team[] all = values();
|
|
||||||
|
|
||||||
Team(Color color){
|
Team(Color color){
|
||||||
this.color = color;
|
this.color = color;
|
||||||
intColor = Color.rgba8888(color);
|
intColor = Color.rgba8888(color);
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ import io.anuke.mindustry.world.Tile;
|
|||||||
import io.anuke.ucore.util.ThreadArray;
|
import io.anuke.ucore.util.ThreadArray;
|
||||||
import io.anuke.ucore.util.ThreadSet;
|
import io.anuke.ucore.util.ThreadSet;
|
||||||
|
|
||||||
/**Class for various team-based utilities.*/
|
/**
|
||||||
|
* Class for various team-based utilities.
|
||||||
|
*/
|
||||||
public class TeamInfo{
|
public class TeamInfo{
|
||||||
private ObjectMap<Team, TeamData> map = new ObjectMap<>();
|
private ObjectMap<Team, TeamData> map = new ObjectMap<>();
|
||||||
private ThreadSet<Team> allies = new ThreadSet<>(),
|
private ThreadSet<Team> allies = new ThreadSet<>(),
|
||||||
@@ -18,20 +20,27 @@ public class TeamInfo {
|
|||||||
private int allyBits = 0;
|
private int allyBits = 0;
|
||||||
private int enemyBits = 0;
|
private int enemyBits = 0;
|
||||||
|
|
||||||
/**Returns all teams on a side.*/
|
/**
|
||||||
|
* Returns all teams on a side.
|
||||||
|
*/
|
||||||
public ObjectSet<TeamData> getTeams(boolean ally){
|
public ObjectSet<TeamData> getTeams(boolean ally){
|
||||||
return ally ? allyData : enemyData;
|
return ally ? allyData : enemyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns all team data.*/
|
/**
|
||||||
|
* Returns all team data.
|
||||||
|
*/
|
||||||
public ObjectSet<TeamData> getTeams(){
|
public ObjectSet<TeamData> getTeams(){
|
||||||
return allTeamData;
|
return allTeamData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Register a team.
|
/**
|
||||||
|
* Register a team.
|
||||||
|
*
|
||||||
* @param team The team type enum.
|
* @param team The team type enum.
|
||||||
* @param ally Whether this team is an ally with the player or an enemy with the player.
|
* @param ally Whether this team is an ally with the player or an enemy with the player.
|
||||||
* In PvP situations with dedicated servers, the sides can be arbitrary.*/
|
* In PvP situations with dedicated servers, the sides can be arbitrary.
|
||||||
|
*/
|
||||||
public void add(Team team, boolean ally){
|
public void add(Team team, boolean ally){
|
||||||
if(has(team)) throw new RuntimeException("Can't define team information twice!");
|
if(has(team)) throw new RuntimeException("Can't define team information twice!");
|
||||||
|
|
||||||
@@ -53,19 +62,25 @@ public class TeamInfo {
|
|||||||
map.put(team, data);
|
map.put(team, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns team data by type. Call {@link #has(Team)} first to make sure it's active!*/
|
/**
|
||||||
|
* Returns team data by type. Call {@link #has(Team)} first to make sure it's active!
|
||||||
|
*/
|
||||||
public TeamData get(Team team){
|
public TeamData get(Team team){
|
||||||
if(!has(team)) throw new RuntimeException("This team is not active! Check has() before calling get().");
|
if(!has(team)) throw new RuntimeException("This team is not active! Check has() before calling get().");
|
||||||
return map.get(team);
|
return map.get(team);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether the specified team is active, e.g. whether it is participating in the game.*/
|
/**
|
||||||
|
* Returns whether the specified team is active, e.g. whether it is participating in the game.
|
||||||
|
*/
|
||||||
public boolean has(Team team){
|
public boolean has(Team team){
|
||||||
return map.containsKey(team);
|
return map.containsKey(team);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a set of all teams that are enemies of this team.
|
/**
|
||||||
* For teams not active, an empty set is returned.*/
|
* Returns a set of all teams that are enemies of this team.
|
||||||
|
* For teams not active, an empty set is returned.
|
||||||
|
*/
|
||||||
public ObjectSet<Team> enemiesOf(Team team){
|
public ObjectSet<Team> enemiesOf(Team team){
|
||||||
boolean ally = allies.contains(team);
|
boolean ally = allies.contains(team);
|
||||||
boolean enemy = enemies.contains(team);
|
boolean enemy = enemies.contains(team);
|
||||||
@@ -76,8 +91,10 @@ public class TeamInfo {
|
|||||||
return ally ? enemies : allies;
|
return ally ? enemies : allies;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a set of all teams that are allies of this team.
|
/**
|
||||||
* For teams not active, an empty set is returned.*/
|
* Returns a set of all teams that are allies of this team.
|
||||||
|
* For teams not active, an empty set is returned.
|
||||||
|
*/
|
||||||
public ObjectSet<Team> alliesOf(Team team){
|
public ObjectSet<Team> alliesOf(Team team){
|
||||||
boolean ally = allies.contains(team);
|
boolean ally = allies.contains(team);
|
||||||
boolean enemy = enemies.contains(team);
|
boolean enemy = enemies.contains(team);
|
||||||
@@ -88,8 +105,10 @@ public class TeamInfo {
|
|||||||
return !ally ? enemies : allies;
|
return !ally ? enemies : allies;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a set of all teams that are enemies of this team.
|
/**
|
||||||
* For teams not active, an empty set is returned.*/
|
* Returns a set of all teams that are enemies of this team.
|
||||||
|
* For teams not active, an empty set is returned.
|
||||||
|
*/
|
||||||
public ObjectSet<TeamData> enemyDataOf(Team team){
|
public ObjectSet<TeamData> enemyDataOf(Team team){
|
||||||
boolean ally = allies.contains(team);
|
boolean ally = allies.contains(team);
|
||||||
boolean enemy = enemies.contains(team);
|
boolean enemy = enemies.contains(team);
|
||||||
@@ -100,7 +119,9 @@ public class TeamInfo {
|
|||||||
return ally ? enemyData : allyData;
|
return ally ? enemyData : allyData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether or not these two teams are enemies.*/
|
/**
|
||||||
|
* Returns whether or not these two teams are enemies.
|
||||||
|
*/
|
||||||
public boolean areEnemies(Team team, Team other){
|
public boolean areEnemies(Team team, Team other){
|
||||||
if(team == other) return false; //fast fail to be more efficient
|
if(team == other) return false; //fast fail to be more efficient
|
||||||
boolean ally = (allyBits & (1 << team.ordinal())) != 0;
|
boolean ally = (allyBits & (1 << team.ordinal())) != 0;
|
||||||
|
|||||||
@@ -5,37 +5,54 @@ import io.anuke.ucore.scene.ui.layout.Table;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.control;
|
import static io.anuke.mindustry.Vars.control;
|
||||||
|
|
||||||
/**Base interface for an unlockable content type.*/
|
/**
|
||||||
|
* Base interface for an unlockable content type.
|
||||||
|
*/
|
||||||
public interface UnlockableContent extends Content{
|
public interface UnlockableContent extends Content{
|
||||||
|
|
||||||
/**Returns the unqiue name of this piece of content.
|
/**
|
||||||
|
* Returns the unqiue name of this piece of content.
|
||||||
* The name only needs to be unique for all content of this type.
|
* The name only needs to be unique for all content of this type.
|
||||||
* Do not use IDs for names! Make sure this string stays constant with each update unless removed.
|
* Do not use IDs for names! Make sure this string stays constant with each update unless removed.
|
||||||
* (e.g. having a recipe and a block, both with name "wall" is fine, as they are different types).*/
|
* (e.g. having a recipe and a block, both with name "wall" is fine, as they are different types).
|
||||||
|
*/
|
||||||
String getContentName();
|
String getContentName();
|
||||||
|
|
||||||
/**Returns the localized name of this content.*/
|
/**
|
||||||
|
* Returns the localized name of this content.
|
||||||
|
*/
|
||||||
String localizedName();
|
String localizedName();
|
||||||
|
|
||||||
TextureRegion getContentIcon();
|
TextureRegion getContentIcon();
|
||||||
|
|
||||||
/**This should show all necessary info about this content in the specified table.*/
|
/**
|
||||||
|
* This should show all necessary info about this content in the specified table.
|
||||||
|
*/
|
||||||
void displayInfo(Table table);
|
void displayInfo(Table table);
|
||||||
|
|
||||||
/**Called when this content is unlocked. Use this to unlock other related content.*/
|
/**
|
||||||
default void onUnlock(){}
|
* Called when this content is unlocked. Use this to unlock other related content.
|
||||||
|
*/
|
||||||
|
default void onUnlock(){
|
||||||
|
}
|
||||||
|
|
||||||
/**Whether this content is always hidden in the content info dialog.*/
|
/**
|
||||||
|
* Whether this content is always hidden in the content info dialog.
|
||||||
|
*/
|
||||||
default boolean isHidden(){
|
default boolean isHidden(){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Lists the content that must be unlocked in order for this specific content to become unlocked. May return null.*/
|
/**
|
||||||
|
* Lists the content that must be unlocked in order for this specific content to become unlocked. May return null.
|
||||||
|
*/
|
||||||
default UnlockableContent[] getDependencies(){
|
default UnlockableContent[] getDependencies(){
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether dependencies are satisfied for unlocking this content.*/
|
/**
|
||||||
|
* Returns whether dependencies are satisfied for unlocking this content.
|
||||||
|
*/
|
||||||
default boolean canBeUnlocked(){
|
default boolean canBeUnlocked(){
|
||||||
UnlockableContent[] depend = getDependencies();
|
UnlockableContent[] depend = getDependencies();
|
||||||
if(depend == null){
|
if(depend == null){
|
||||||
|
|||||||
@@ -32,22 +32,9 @@ public class BlockRenderer{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BlockRequest implements Comparable<BlockRequest>{
|
/**
|
||||||
Tile tile;
|
* Process all blocks to draw, simultaneously drawing block shadows and static blocks.
|
||||||
Layer layer;
|
*/
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(BlockRequest other){
|
|
||||||
return layer.compareTo(other.layer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString(){
|
|
||||||
return tile.block().name + ":" + layer.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Process all blocks to draw, simultaneously drawing block shadows and static blocks.*/
|
|
||||||
public void processBlocks(){
|
public void processBlocks(){
|
||||||
requestidx = 0;
|
requestidx = 0;
|
||||||
lastLayer = null;
|
lastLayer = null;
|
||||||
@@ -198,9 +185,11 @@ public class BlockRenderer{
|
|||||||
floorRenderer.drawFloor();
|
floorRenderer.drawFloor();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void layerBegins(Layer layer){}
|
private void layerBegins(Layer layer){
|
||||||
|
}
|
||||||
|
|
||||||
private void layerEnds(Layer layer){}
|
private void layerEnds(Layer layer){
|
||||||
|
}
|
||||||
|
|
||||||
private void addRequest(Tile tile, Layer layer){
|
private void addRequest(Tile tile, Layer layer){
|
||||||
if(requestidx >= requests.size){
|
if(requestidx >= requests.size){
|
||||||
@@ -214,4 +203,19 @@ public class BlockRenderer{
|
|||||||
r.layer = layer;
|
r.layer = layer;
|
||||||
requestidx++;
|
requestidx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class BlockRequest implements Comparable<BlockRequest>{
|
||||||
|
Tile tile;
|
||||||
|
Layer layer;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(BlockRequest other){
|
||||||
|
return layer.compareTo(other.layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString(){
|
||||||
|
return tile.block().name + ":" + layer.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,35 @@ public class FloorRenderer {
|
|||||||
Events.on(WorldLoadGraphicsEvent.class, this::clearTiles);
|
Events.on(WorldLoadGraphicsEvent.class, this::clearTiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ShaderProgram createDefaultShader(){
|
||||||
|
String vertexShader = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
|
||||||
|
+ "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
|
||||||
|
+ "uniform mat4 u_projTrans;\n" //
|
||||||
|
+ "varying vec2 v_texCoords;\n" //
|
||||||
|
+ "\n" //
|
||||||
|
+ "void main()\n" //
|
||||||
|
+ "{\n" //
|
||||||
|
+ " v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
|
||||||
|
+ " gl_Position = u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
|
||||||
|
+ "}\n";
|
||||||
|
String fragmentShader = "#ifdef GL_ES\n" //
|
||||||
|
+ "#define LOWP lowp\n" //
|
||||||
|
+ "precision mediump float;\n" //
|
||||||
|
+ "#else\n" //
|
||||||
|
+ "#define LOWP \n" //
|
||||||
|
+ "#endif\n" //
|
||||||
|
+ "varying vec2 v_texCoords;\n" //
|
||||||
|
+ "uniform sampler2D u_texture;\n" //
|
||||||
|
+ "void main()\n"//
|
||||||
|
+ "{\n" //
|
||||||
|
+ " gl_FragColor = texture2D(u_texture, v_texCoords);\n" //
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader);
|
||||||
|
if(!shader.isCompiled()) throw new IllegalArgumentException("Error compiling shader: " + shader.getLog());
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
public void drawFloor(){
|
public void drawFloor(){
|
||||||
if(cache == null){
|
if(cache == null){
|
||||||
return;
|
return;
|
||||||
@@ -211,10 +240,6 @@ public class FloorRenderer {
|
|||||||
chunk.caches[layer.ordinal()] = cbatch.getLastCache();
|
chunk.caches[layer.ordinal()] = cbatch.getLastCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Chunk{
|
|
||||||
int[] caches = new int[CacheLayer.values().length];
|
|
||||||
}
|
|
||||||
|
|
||||||
public void clearTiles(){
|
public void clearTiles(){
|
||||||
if(cbatch != null) cbatch.dispose();
|
if(cbatch != null) cbatch.dispose();
|
||||||
|
|
||||||
@@ -240,32 +265,7 @@ public class FloorRenderer {
|
|||||||
Log.info("Time to cache: {0}", Timers.elapsed());
|
Log.info("Time to cache: {0}", Timers.elapsed());
|
||||||
}
|
}
|
||||||
|
|
||||||
static ShaderProgram createDefaultShader () {
|
private class Chunk{
|
||||||
String vertexShader = "attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
|
int[] caches = new int[CacheLayer.values().length];
|
||||||
+ "attribute vec2 " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
|
|
||||||
+ "uniform mat4 u_projTrans;\n" //
|
|
||||||
+ "varying vec2 v_texCoords;\n" //
|
|
||||||
+ "\n" //
|
|
||||||
+ "void main()\n" //
|
|
||||||
+ "{\n" //
|
|
||||||
+ " v_texCoords = " + ShaderProgram.TEXCOORD_ATTRIBUTE + "0;\n" //
|
|
||||||
+ " gl_Position = u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n" //
|
|
||||||
+ "}\n";
|
|
||||||
String fragmentShader = "#ifdef GL_ES\n" //
|
|
||||||
+ "#define LOWP lowp\n" //
|
|
||||||
+ "precision mediump float;\n" //
|
|
||||||
+ "#else\n" //
|
|
||||||
+ "#define LOWP \n" //
|
|
||||||
+ "#endif\n" //
|
|
||||||
+ "varying vec2 v_texCoords;\n" //
|
|
||||||
+ "uniform sampler2D u_texture;\n" //
|
|
||||||
+ "void main()\n"//
|
|
||||||
+ "{\n" //
|
|
||||||
+ " gl_FragColor = texture2D(u_texture, v_texCoords);\n" //
|
|
||||||
+ "}";
|
|
||||||
|
|
||||||
ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader);
|
|
||||||
if (!shader.isCompiled()) throw new IllegalArgumentException("Error compiling shader: " + shader.getLog());
|
|
||||||
return shader;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
/**Used for rendering fog of war. A framebuffer is used for this.*/
|
/**
|
||||||
|
* Used for rendering fog of war. A framebuffer is used for this.
|
||||||
|
*/
|
||||||
public class FogRenderer implements Disposable{
|
public class FogRenderer implements Disposable{
|
||||||
private TextureRegion region = new TextureRegion();
|
private TextureRegion region = new TextureRegion();
|
||||||
private FrameBuffer buffer;
|
private FrameBuffer buffer;
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
package io.anuke.mindustry.graphics;
|
package io.anuke.mindustry.graphics;
|
||||||
|
|
||||||
public enum Layer{
|
public enum Layer{
|
||||||
/**Base block layer.*/
|
/**
|
||||||
|
* Base block layer.
|
||||||
|
*/
|
||||||
block,
|
block,
|
||||||
/**for placement*/
|
/**
|
||||||
|
* for placement
|
||||||
|
*/
|
||||||
placement,
|
placement,
|
||||||
/**First overlay. Stuff like conveyor items.*/
|
/**
|
||||||
|
* First overlay. Stuff like conveyor items.
|
||||||
|
*/
|
||||||
overlay,
|
overlay,
|
||||||
/**"High" blocks, like turrets.*/
|
/**
|
||||||
|
* "High" blocks, like turrets.
|
||||||
|
*/
|
||||||
turret,
|
turret,
|
||||||
/**Power lasers.*/
|
/**
|
||||||
|
* Power lasers.
|
||||||
|
*/
|
||||||
power,
|
power,
|
||||||
/**Extra lasers, like healing turrets.*/
|
/**
|
||||||
|
* Extra lasers, like healing turrets.
|
||||||
|
*/
|
||||||
laser
|
laser
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import io.anuke.mindustry.game.TeamInfo.TeamData;
|
|||||||
import io.anuke.mindustry.input.InputHandler;
|
import io.anuke.mindustry.input.InputHandler;
|
||||||
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.consumers.Consume;
|
|
||||||
import io.anuke.mindustry.world.meta.BlockBar;
|
import io.anuke.mindustry.world.meta.BlockBar;
|
||||||
import io.anuke.ucore.core.Graphics;
|
import io.anuke.ucore.core.Graphics;
|
||||||
import io.anuke.ucore.core.Settings;
|
import io.anuke.ucore.core.Settings;
|
||||||
|
|||||||
@@ -8,7 +8,9 @@ import io.anuke.ucore.graphics.Fill;
|
|||||||
import io.anuke.ucore.graphics.Lines;
|
import io.anuke.ucore.graphics.Lines;
|
||||||
import io.anuke.ucore.util.Mathf;
|
import io.anuke.ucore.util.Mathf;
|
||||||
|
|
||||||
/**Class that renders a trail.*/
|
/**
|
||||||
|
* Class that renders a trail.
|
||||||
|
*/
|
||||||
public class Trail{
|
public class Trail{
|
||||||
private final static float maxJump = 15f;
|
private final static float maxJump = 15f;
|
||||||
private final int length;
|
private final int length;
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package io.anuke.mindustry.input;
|
|||||||
import io.anuke.ucore.function.Callable;
|
import io.anuke.ucore.function.Callable;
|
||||||
import io.anuke.ucore.scene.utils.Cursors;
|
import io.anuke.ucore.scene.utils.Cursors;
|
||||||
|
|
||||||
/**Type of cursor for displaying on desktop.*/
|
/**
|
||||||
|
* Type of cursor for displaying on desktop.
|
||||||
|
*/
|
||||||
public enum CursorType{
|
public enum CursorType{
|
||||||
normal(Cursors::restoreCursor),
|
normal(Cursors::restoreCursor),
|
||||||
hand(Cursors::setHand),
|
hand(Cursors::setHand),
|
||||||
@@ -16,7 +18,9 @@ public enum CursorType {
|
|||||||
this.call = call;
|
this.call = call;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sets the current system cursor to this.*/
|
/**
|
||||||
|
* Sets the current system cursor to this.
|
||||||
|
*/
|
||||||
void set(){
|
void set(){
|
||||||
call.run();
|
call.run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,19 +27,26 @@ import static io.anuke.mindustry.input.CursorType.*;
|
|||||||
import static io.anuke.mindustry.input.PlaceMode.*;
|
import static io.anuke.mindustry.input.PlaceMode.*;
|
||||||
|
|
||||||
public class DesktopInput extends InputHandler{
|
public class DesktopInput extends InputHandler{
|
||||||
|
private final String section;
|
||||||
//controller info
|
//controller info
|
||||||
private float controlx, controly;
|
private float controlx, controly;
|
||||||
private boolean controlling;
|
private boolean controlling;
|
||||||
private final String section;
|
/**
|
||||||
|
* Current cursor type.
|
||||||
/**Current cursor type.*/
|
*/
|
||||||
private CursorType cursorType = normal;
|
private CursorType cursorType = normal;
|
||||||
|
|
||||||
/**Position where the player started dragging a line.*/
|
/**
|
||||||
|
* Position where the player started dragging a line.
|
||||||
|
*/
|
||||||
private int selectX, selectY;
|
private int selectX, selectY;
|
||||||
/**Whether selecting mode is active.*/
|
/**
|
||||||
|
* Whether selecting mode is active.
|
||||||
|
*/
|
||||||
private PlaceMode mode;
|
private PlaceMode mode;
|
||||||
/**Animation scale for line.*/
|
/**
|
||||||
|
* Animation scale for line.
|
||||||
|
*/
|
||||||
private float selectScale;
|
private float selectScale;
|
||||||
|
|
||||||
public DesktopInput(Player player){
|
public DesktopInput(Player player){
|
||||||
@@ -47,7 +54,9 @@ public class DesktopInput extends InputHandler{
|
|||||||
this.section = "player_" + (player.playerIndex + 1);
|
this.section = "player_" + (player.playerIndex + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Draws a placement icon for a specific block.*/
|
/**
|
||||||
|
* Draws a placement icon for a specific block.
|
||||||
|
*/
|
||||||
void drawPlace(int x, int y, Block block, int rotation){
|
void drawPlace(int x, int y, Block block, int rotation){
|
||||||
if(validPlace(x, y, block, rotation)){
|
if(validPlace(x, y, block, rotation)){
|
||||||
Draw.color();
|
Draw.color();
|
||||||
|
|||||||
@@ -33,12 +33,18 @@ import io.anuke.ucore.util.Translator;
|
|||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public abstract class InputHandler extends InputAdapter{
|
public abstract class InputHandler extends InputAdapter{
|
||||||
/**Used for dropping items.*/
|
/**
|
||||||
|
* Used for dropping items.
|
||||||
|
*/
|
||||||
final static float playerSelectRange = mobile ? 17f : 11f;
|
final static float playerSelectRange = mobile ? 17f : 11f;
|
||||||
/**Maximum line length.*/
|
/**
|
||||||
|
* Maximum line length.
|
||||||
|
*/
|
||||||
final static int maxLength = 100;
|
final static int maxLength = 100;
|
||||||
final static Translator stackTrns = new Translator();
|
final static Translator stackTrns = new Translator();
|
||||||
/**Distance on the back from where items originate.*/
|
/**
|
||||||
|
* Distance on the back from where items originate.
|
||||||
|
*/
|
||||||
final static float backTrns = 3f;
|
final static float backTrns = 3f;
|
||||||
|
|
||||||
public final Player player;
|
public final Player player;
|
||||||
@@ -57,6 +63,73 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
|
|
||||||
//methods to override
|
//methods to override
|
||||||
|
|
||||||
|
@Remote(targets = Loc.client, called = Loc.server, in = In.entities)
|
||||||
|
public static void dropItem(Player player, float angle){
|
||||||
|
if(Net.server() && !player.inventory.hasItem()){
|
||||||
|
throw new ValidateException(player, "Player cannot drop an item.");
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemDrop.create(player.inventory.getItem().item, player.inventory.getItem().amount, player.x, player.y, angle);
|
||||||
|
player.inventory.clearItem();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(targets = Loc.both, forward = true, called = Loc.server, in = In.blocks)
|
||||||
|
public static void transferInventory(Player player, Tile tile){
|
||||||
|
if(Net.server() && (!player.inventory.hasItem() || player.isTransferring)){
|
||||||
|
throw new ValidateException(player, "Player cannot transfer an item.");
|
||||||
|
}
|
||||||
|
|
||||||
|
threads.run(() -> {
|
||||||
|
if(player == null || tile.entity == null) return;
|
||||||
|
|
||||||
|
player.isTransferring = true;
|
||||||
|
|
||||||
|
ItemStack stack = player.inventory.getItem();
|
||||||
|
int accepted = tile.block().acceptStack(stack.item, stack.amount, tile, player);
|
||||||
|
|
||||||
|
boolean clear = stack.amount == accepted;
|
||||||
|
int sent = Mathf.clamp(accepted / 4, 1, 8);
|
||||||
|
int removed = accepted / sent;
|
||||||
|
int[] remaining = {accepted, accepted};
|
||||||
|
|
||||||
|
for(int i = 0; i < sent; i++){
|
||||||
|
boolean end = i == sent - 1;
|
||||||
|
Timers.run(i * 3, () -> {
|
||||||
|
tile.block().getStackOffset(stack.item, tile, stackTrns);
|
||||||
|
|
||||||
|
ItemTransfer.create(stack.item,
|
||||||
|
player.x + Angles.trnsx(player.rotation + 180f, backTrns), player.y + Angles.trnsy(player.rotation + 180f, backTrns),
|
||||||
|
new Translator(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> {
|
||||||
|
|
||||||
|
tile.block().handleStack(stack.item, removed, tile, player);
|
||||||
|
remaining[1] -= removed;
|
||||||
|
|
||||||
|
if(end && remaining[1] > 0){
|
||||||
|
tile.block().handleStack(stack.item, remaining[1], tile, player);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
stack.amount -= removed;
|
||||||
|
remaining[0] -= removed;
|
||||||
|
|
||||||
|
if(end){
|
||||||
|
stack.amount -= remaining[0];
|
||||||
|
if(clear){
|
||||||
|
player.inventory.clearItem();
|
||||||
|
}
|
||||||
|
player.isTransferring = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Remote(targets = Loc.both, called = Loc.server, forward = true, in = In.blocks)
|
||||||
|
public static void onTileTapped(Player player, Tile tile){
|
||||||
|
if(tile == null || player == null) return;
|
||||||
|
tile.block().tapped(tile, player);
|
||||||
|
}
|
||||||
|
|
||||||
public void update(){
|
public void update(){
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -97,7 +170,9 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**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.target();
|
||||||
|
|
||||||
@@ -153,7 +228,9 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
return consumed;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Tries to select the player to drop off items, returns true if successful.*/
|
/**
|
||||||
|
* Tries to select the player to drop off items, returns true if successful.
|
||||||
|
*/
|
||||||
boolean tryTapPlayer(float x, float y){
|
boolean tryTapPlayer(float x, float y){
|
||||||
if(canTapPlayer(x, y)){
|
if(canTapPlayer(x, y)){
|
||||||
droppingItem = true;
|
droppingItem = true;
|
||||||
@@ -166,7 +243,9 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
return Vector2.dst(x, y, player.x, player.y) <= playerSelectRange && player.inventory.hasItem();
|
return Vector2.dst(x, y, player.x, player.y) <= playerSelectRange && player.inventory.hasItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Tries to begin mining a tile, returns true if successful.*/
|
/**
|
||||||
|
* Tries to begin mining a tile, returns true if successful.
|
||||||
|
*/
|
||||||
boolean tryBeginMine(Tile tile){
|
boolean tryBeginMine(Tile tile){
|
||||||
if(canMine(tile)){
|
if(canMine(tile)){
|
||||||
//if a block is clicked twice, reset it
|
//if a block is clicked twice, reset it
|
||||||
@@ -185,7 +264,9 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
&& tile.block() == Blocks.air && player.distanceTo(tile.worldx(), tile.worldy()) <= Player.mineDistance;
|
&& tile.block() == Blocks.air && player.distanceTo(tile.worldx(), tile.worldy()) <= Player.mineDistance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the tile at the specified MOUSE coordinates.*/
|
/**
|
||||||
|
* Returns the tile at the specified MOUSE coordinates.
|
||||||
|
*/
|
||||||
Tile tileAt(float x, float y){
|
Tile tileAt(float x, float y){
|
||||||
Vector2 vec = Graphics.world(x, y);
|
Vector2 vec = Graphics.world(x, y);
|
||||||
if(isPlacing()){
|
if(isPlacing()){
|
||||||
@@ -279,71 +360,4 @@ public abstract class InputHandler extends InputAdapter{
|
|||||||
player.addBuildRequest(new BuildRequest(tile.x, tile.y));
|
player.addBuildRequest(new BuildRequest(tile.x, tile.y));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(targets = Loc.client, called = Loc.server, in = In.entities)
|
|
||||||
public static void dropItem(Player player, float angle){
|
|
||||||
if(Net.server() && !player.inventory.hasItem()){
|
|
||||||
throw new ValidateException(player, "Player cannot drop an item.");
|
|
||||||
}
|
|
||||||
|
|
||||||
ItemDrop.create(player.inventory.getItem().item, player.inventory.getItem().amount, player.x, player.y, angle);
|
|
||||||
player.inventory.clearItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(targets = Loc.both, forward = true, called = Loc.server, in = In.blocks)
|
|
||||||
public static void transferInventory(Player player, Tile tile){
|
|
||||||
if(Net.server() && (!player.inventory.hasItem() || player.isTransferring)) {
|
|
||||||
throw new ValidateException(player, "Player cannot transfer an item.");
|
|
||||||
}
|
|
||||||
|
|
||||||
threads.run(() -> {
|
|
||||||
if (player == null || tile.entity == null) return;
|
|
||||||
|
|
||||||
player.isTransferring = true;
|
|
||||||
|
|
||||||
ItemStack stack = player.inventory.getItem();
|
|
||||||
int accepted = tile.block().acceptStack(stack.item, stack.amount, tile, player);
|
|
||||||
|
|
||||||
boolean clear = stack.amount == accepted;
|
|
||||||
int sent = Mathf.clamp(accepted / 4, 1, 8);
|
|
||||||
int removed = accepted / sent;
|
|
||||||
int[] remaining = {accepted, accepted};
|
|
||||||
|
|
||||||
for (int i = 0; i < sent; i++) {
|
|
||||||
boolean end = i == sent - 1;
|
|
||||||
Timers.run(i * 3, () -> {
|
|
||||||
tile.block().getStackOffset(stack.item, tile, stackTrns);
|
|
||||||
|
|
||||||
ItemTransfer.create(stack.item,
|
|
||||||
player.x + Angles.trnsx(player.rotation + 180f, backTrns), player.y + Angles.trnsy(player.rotation + 180f, backTrns),
|
|
||||||
new Translator(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> {
|
|
||||||
|
|
||||||
tile.block().handleStack(stack.item, removed, tile, player);
|
|
||||||
remaining[1] -= removed;
|
|
||||||
|
|
||||||
if (end && remaining[1] > 0) {
|
|
||||||
tile.block().handleStack(stack.item, remaining[1], tile, player);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
stack.amount -= removed;
|
|
||||||
remaining[0] -= removed;
|
|
||||||
|
|
||||||
if (end) {
|
|
||||||
stack.amount -= remaining[0];
|
|
||||||
if (clear) {
|
|
||||||
player.inventory.clearItem();
|
|
||||||
}
|
|
||||||
player.isTransferring = false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Remote(targets = Loc.both, called = Loc.server, forward = true, in = In.blocks)
|
|
||||||
public static void onTileTapped(Player player, Tile tile){
|
|
||||||
if(tile == null || player == null) return;
|
|
||||||
tile.block().tapped(tile, player);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,11 +39,14 @@ import static io.anuke.mindustry.Vars.*;
|
|||||||
import static io.anuke.mindustry.input.PlaceMode.*;
|
import static io.anuke.mindustry.input.PlaceMode.*;
|
||||||
|
|
||||||
public class MobileInput extends InputHandler implements GestureListener{
|
public class MobileInput extends InputHandler implements GestureListener{
|
||||||
private static Rectangle r1 = new Rectangle(), r2 = new Rectangle();
|
/**
|
||||||
|
* Maximum speed the player can pan.
|
||||||
/**Maximum speed the player can pan.*/
|
*/
|
||||||
private static final float maxPanSpeed = 1.3f;
|
private static final float maxPanSpeed = 1.3f;
|
||||||
/**Distance to edge of screen to start panning.*/
|
private static Rectangle r1 = new Rectangle(), r2 = new Rectangle();
|
||||||
|
/**
|
||||||
|
* Distance to edge of screen to start panning.
|
||||||
|
*/
|
||||||
private final float edgePan = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(60f);
|
private final float edgePan = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(60f);
|
||||||
|
|
||||||
//gesture data
|
//gesture data
|
||||||
@@ -51,31 +54,53 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
private Vector2 vector = new Vector2();
|
private Vector2 vector = new Vector2();
|
||||||
private float initzoom = -1;
|
private float initzoom = -1;
|
||||||
private boolean zoomed = false;
|
private boolean zoomed = false;
|
||||||
/**Set of completed guides.*/
|
/**
|
||||||
|
* Set of completed guides.
|
||||||
|
*/
|
||||||
private ObjectSet<String> guides = new ObjectSet<>();
|
private ObjectSet<String> guides = new ObjectSet<>();
|
||||||
|
|
||||||
/**Position where the player started dragging a line.*/
|
/**
|
||||||
|
* Position where the player started dragging a line.
|
||||||
|
*/
|
||||||
private int lineStartX, lineStartY;
|
private int lineStartX, lineStartY;
|
||||||
|
|
||||||
/**Animation scale for line.*/
|
/**
|
||||||
|
* Animation scale for line.
|
||||||
|
*/
|
||||||
private float lineScale;
|
private float lineScale;
|
||||||
/**Animation data for crosshair.*/
|
/**
|
||||||
|
* Animation data for crosshair.
|
||||||
|
*/
|
||||||
private float crosshairScale;
|
private float crosshairScale;
|
||||||
private TargetTrait lastTarget;
|
private TargetTrait lastTarget;
|
||||||
|
|
||||||
/**List of currently selected tiles to place.*/
|
/**
|
||||||
|
* List of currently selected tiles to place.
|
||||||
|
*/
|
||||||
private Array<PlaceRequest> selection = new Array<>();
|
private Array<PlaceRequest> selection = new Array<>();
|
||||||
/**Place requests to be removed.*/
|
/**
|
||||||
|
* Place requests to be removed.
|
||||||
|
*/
|
||||||
private Array<PlaceRequest> removals = new Array<>();
|
private Array<PlaceRequest> removals = new Array<>();
|
||||||
/**Whether or not the player is currently shifting all placed tiles.*/
|
/**
|
||||||
|
* Whether or not the player is currently shifting all placed tiles.
|
||||||
|
*/
|
||||||
private boolean selecting;
|
private boolean selecting;
|
||||||
/**Whether the player is currently in line-place mode.*/
|
/**
|
||||||
|
* Whether the player is currently in line-place mode.
|
||||||
|
*/
|
||||||
private boolean lineMode;
|
private boolean lineMode;
|
||||||
/**Current place mode.*/
|
/**
|
||||||
|
* Current place mode.
|
||||||
|
*/
|
||||||
private PlaceMode mode = none;
|
private PlaceMode mode = none;
|
||||||
/**Whether no recipe was available when switching to break mode.*/
|
/**
|
||||||
|
* Whether no recipe was available when switching to break mode.
|
||||||
|
*/
|
||||||
private Recipe lastRecipe;
|
private Recipe lastRecipe;
|
||||||
/**Last placed request. Used for drawing block overlay.*/
|
/**
|
||||||
|
* Last placed request. Used for drawing block overlay.
|
||||||
|
*/
|
||||||
private PlaceRequest lastPlaced;
|
private PlaceRequest lastPlaced;
|
||||||
|
|
||||||
public MobileInput(Player player){
|
public MobileInput(Player player){
|
||||||
@@ -85,7 +110,9 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
|
|
||||||
//region utility methods
|
//region utility methods
|
||||||
|
|
||||||
/**Check and assign targets for a specific position.*/
|
/**
|
||||||
|
* Check and assign targets for a specific position.
|
||||||
|
*/
|
||||||
void checkTargets(float x, float y){
|
void checkTargets(float x, float y){
|
||||||
synchronized(Entities.entityLock){
|
synchronized(Entities.entityLock){
|
||||||
Unit unit = Units.getClosestEnemy(player.getTeam(), x, y, 20f, u -> true);
|
Unit unit = Units.getClosestEnemy(player.getTeam(), x, y, 20f, u -> true);
|
||||||
@@ -103,12 +130,16 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether this tile is in the list of requests, or at least colliding with one.*/
|
/**
|
||||||
|
* Returns whether this tile is in the list of requests, or at least colliding with one.
|
||||||
|
*/
|
||||||
boolean hasRequest(Tile tile){
|
boolean hasRequest(Tile tile){
|
||||||
return getRequest(tile) != null;
|
return getRequest(tile) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns whether this block overlaps any selection requests.*/
|
/**
|
||||||
|
* Returns whether this block overlaps any selection requests.
|
||||||
|
*/
|
||||||
boolean checkOverlapPlacement(int x, int y, Block block){
|
boolean checkOverlapPlacement(int x, int y, Block block){
|
||||||
r2.setSize(block.size * tilesize);
|
r2.setSize(block.size * tilesize);
|
||||||
r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset());
|
r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset());
|
||||||
@@ -128,7 +159,9 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the selection request that overlaps this tile, or null.*/
|
/**
|
||||||
|
* Returns the selection request that overlaps this tile, or null.
|
||||||
|
*/
|
||||||
PlaceRequest getRequest(Tile tile){
|
PlaceRequest getRequest(Tile tile){
|
||||||
r2.setSize(tilesize);
|
r2.setSize(tilesize);
|
||||||
r2.setCenter(tile.worldx(), tile.worldy());
|
r2.setCenter(tile.worldx(), tile.worldy());
|
||||||
@@ -733,8 +766,15 @@ public class MobileInput extends InputHandler implements GestureListener{
|
|||||||
zoomed = false;
|
zoomed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public boolean touchDown(float x, float y, int pointer, int button) { return false; }
|
@Override
|
||||||
@Override public boolean fling(float velocityX, float velocityY, int button) { return false; }
|
public boolean touchDown(float x, float y, int pointer, int button){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean fling(float velocityX, float velocityY, int button){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ public class PlaceUtils {
|
|||||||
private static final NormalizeResult result = new NormalizeResult();
|
private static final NormalizeResult result = new NormalizeResult();
|
||||||
private static final NormalizeDrawResult drawResult = new NormalizeDrawResult();
|
private static final NormalizeDrawResult drawResult = new NormalizeDrawResult();
|
||||||
|
|
||||||
/**Normalizes a placement area and returns the result, ready to be used for drawing a rectangle.
|
/**
|
||||||
|
* Normalizes a placement area and returns the result, ready to be used for drawing a rectangle.
|
||||||
* Returned x2 and y2 will <i>always</i> be greater than x and y.
|
* Returned x2 and y2 will <i>always</i> be greater than x and y.
|
||||||
*
|
*
|
||||||
* @param block block that will be drawn
|
* @param block block that will be drawn
|
||||||
@@ -45,7 +46,8 @@ public class PlaceUtils {
|
|||||||
return drawResult;
|
return drawResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Normalizes a placement area and returns the result.
|
/**
|
||||||
|
* Normalizes a placement area and returns the result.
|
||||||
* Returned x2 and y2 will <i>always</i> be greater than x and y.
|
* Returned x2 and y2 will <i>always</i> be greater than x and y.
|
||||||
*
|
*
|
||||||
* @param tilex starting X coordinate
|
* @param tilex starting X coordinate
|
||||||
@@ -121,17 +123,23 @@ public class PlaceUtils {
|
|||||||
return Math.abs(x2 - x) > Math.abs(y2 - y);
|
return Math.abs(x2 - x) > Math.abs(y2 - y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns length of greater edge of the selection.*/
|
/**
|
||||||
|
* Returns length of greater edge of the selection.
|
||||||
|
*/
|
||||||
int getLength(){
|
int getLength(){
|
||||||
return Math.max(x2 - x, y2 - y);
|
return Math.max(x2 - x, y2 - y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the X position of a specific index along this area as a line.*/
|
/**
|
||||||
|
* Returns the X position of a specific index along this area as a line.
|
||||||
|
*/
|
||||||
int getScaledX(int i){
|
int getScaledX(int i){
|
||||||
return x + (x2 - x > y2 - y ? i : 0);
|
return x + (x2 - x > y2 - y ? i : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns the Y position of a specific index along this area as a line.*/
|
/**
|
||||||
|
* Returns the Y position of a specific index along this area as a line.
|
||||||
|
*/
|
||||||
int getScaledY(int i){
|
int getScaledY(int i){
|
||||||
return y + (x2 - x > y2 - y ? 0 : i);
|
return y + (x2 - x > y2 - y ? 0 : i);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,15 +7,25 @@ import io.anuke.ucore.function.Supplier;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
public class Map{
|
public class Map{
|
||||||
/**Internal map name. This is the filename, without any extensions.*/
|
/**
|
||||||
|
* Internal map name. This is the filename, without any extensions.
|
||||||
|
*/
|
||||||
public final String name;
|
public final String name;
|
||||||
/**Whether this is a custom map.*/
|
/**
|
||||||
|
* Whether this is a custom map.
|
||||||
|
*/
|
||||||
public final boolean custom;
|
public final boolean custom;
|
||||||
/**Metadata. Author description, display name, etc.*/
|
/**
|
||||||
|
* Metadata. Author description, display name, etc.
|
||||||
|
*/
|
||||||
public final MapMeta meta;
|
public final MapMeta meta;
|
||||||
/**Supplies a new input stream with the data of this map.*/
|
/**
|
||||||
|
* Supplies a new input stream with the data of this map.
|
||||||
|
*/
|
||||||
public final Supplier<InputStream> stream;
|
public final Supplier<InputStream> stream;
|
||||||
/**Preview texture.*/
|
/**
|
||||||
|
* Preview texture.
|
||||||
|
*/
|
||||||
public Texture texture;
|
public Texture texture;
|
||||||
|
|
||||||
public Map(String name, MapMeta meta, boolean custom, Supplier<InputStream> streamSupplier){
|
public Map(String name, MapMeta meta, boolean custom, Supplier<InputStream> streamSupplier){
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ import java.io.DataOutputStream;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
/**Reads and writes map files.*/
|
/**
|
||||||
|
* Reads and writes map files.
|
||||||
|
*/
|
||||||
public class MapIO{
|
public class MapIO{
|
||||||
private static final int version = 0;
|
private static final int version = 0;
|
||||||
private static IntIntMap defaultBlockMap = new IntIntMap();
|
private static IntIntMap defaultBlockMap = new IntIntMap();
|
||||||
@@ -94,21 +96,27 @@ public class MapIO {
|
|||||||
ds.close();
|
ds.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Reads tile data, skipping meta.*/
|
/**
|
||||||
|
* Reads tile data, skipping meta.
|
||||||
|
*/
|
||||||
public static MapTileData readTileData(DataInputStream stream, boolean readOnly) throws IOException{
|
public static MapTileData readTileData(DataInputStream stream, boolean readOnly) throws IOException{
|
||||||
MapMeta meta = readMapMeta(stream);
|
MapMeta meta = readMapMeta(stream);
|
||||||
return readTileData(stream, meta, readOnly);
|
return readTileData(stream, meta, readOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**Does not skip meta. Call after reading meta.*/
|
/**
|
||||||
|
* Does not skip meta. Call after reading meta.
|
||||||
|
*/
|
||||||
public static MapTileData readTileData(DataInputStream stream, MapMeta meta, boolean readOnly) throws IOException{
|
public static MapTileData readTileData(DataInputStream stream, MapMeta meta, boolean readOnly) throws IOException{
|
||||||
byte[] bytes = new byte[stream.available()];
|
byte[] bytes = new byte[stream.available()];
|
||||||
stream.readFully(bytes);
|
stream.readFully(bytes);
|
||||||
return new MapTileData(bytes, meta.width, meta.height, meta.blockMap, readOnly);
|
return new MapTileData(bytes, meta.width, meta.height, meta.blockMap, readOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Reads tile data, skipping meta tags.*/
|
/**
|
||||||
|
* Reads tile data, skipping meta tags.
|
||||||
|
*/
|
||||||
public static MapTileData readTileData(Map map, boolean readOnly){
|
public static MapTileData readTileData(Map map, boolean readOnly){
|
||||||
try(DataInputStream ds = new DataInputStream(map.stream.get())){
|
try(DataInputStream ds = new DataInputStream(map.stream.get())){
|
||||||
return MapIO.readTileData(ds, readOnly);
|
return MapIO.readTileData(ds, readOnly);
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import io.anuke.ucore.util.Bits;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public class MapTileData{
|
public class MapTileData{
|
||||||
/**Tile size: 4 bytes. <br>
|
/**
|
||||||
|
* Tile size: 4 bytes. <br>
|
||||||
* 0: ground tile <br>
|
* 0: ground tile <br>
|
||||||
* 1: wall tile <br>
|
* 1: wall tile <br>
|
||||||
* 2: rotation + team <br>
|
* 2: rotation + team <br>
|
||||||
* 3: link (x/y) <br>
|
* 3: link (x/y) <br>
|
||||||
* 4: elevation <br>*/
|
* 4: elevation <br>
|
||||||
|
*/
|
||||||
private final static int TILE_SIZE = 5;
|
private final static int TILE_SIZE = 5;
|
||||||
|
|
||||||
private final ByteBuffer buffer;
|
private final ByteBuffer buffer;
|
||||||
@@ -59,28 +61,38 @@ public class MapTileData {
|
|||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Write a byte to a specific position.*/
|
/**
|
||||||
|
* Write a byte to a specific position.
|
||||||
|
*/
|
||||||
public void write(int x, int y, DataPosition position, byte data){
|
public void write(int x, int y, DataPosition position, byte data){
|
||||||
buffer.put((x + width * y) * TILE_SIZE + position.ordinal(), data);
|
buffer.put((x + width * y) * TILE_SIZE + position.ordinal(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Gets a byte at a specific position.*/
|
/**
|
||||||
|
* Gets a byte at a specific position.
|
||||||
|
*/
|
||||||
public byte read(int x, int y, DataPosition position){
|
public byte read(int x, int y, DataPosition position){
|
||||||
return buffer.get((x + width * y) * TILE_SIZE + position.ordinal());
|
return buffer.get((x + width * y) * TILE_SIZE + position.ordinal());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Reads and returns the next tile data.*/
|
/**
|
||||||
|
* Reads and returns the next tile data.
|
||||||
|
*/
|
||||||
public TileDataMarker read(TileDataMarker marker){
|
public TileDataMarker read(TileDataMarker marker){
|
||||||
marker.read(buffer);
|
marker.read(buffer);
|
||||||
return marker;
|
return marker;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Writes this tile data marker.*/
|
/**
|
||||||
|
* Writes this tile data marker.
|
||||||
|
*/
|
||||||
public void write(TileDataMarker marker){
|
public void write(TileDataMarker marker){
|
||||||
marker.write(buffer);
|
marker.write(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sets read position to the specified coordinates*/
|
/**
|
||||||
|
* Sets read position to the specified coordinates
|
||||||
|
*/
|
||||||
public void position(int x, int y){
|
public void position(int x, int y){
|
||||||
buffer.position((x + width * y) * TILE_SIZE);
|
buffer.position((x + width * y) * TILE_SIZE);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,30 +17,46 @@ import java.io.*;
|
|||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class Maps implements Disposable{
|
public class Maps implements Disposable{
|
||||||
/**List of all built-in maps.*/
|
/**
|
||||||
|
* List of all built-in maps.
|
||||||
|
*/
|
||||||
private static final String[] defaultMapNames = {};
|
private static final String[] defaultMapNames = {};
|
||||||
/**Tile format version.*/
|
/**
|
||||||
|
* Tile format version.
|
||||||
|
*/
|
||||||
private static final int version = 0;
|
private static final int version = 0;
|
||||||
|
|
||||||
/**Maps map names to the real maps.*/
|
/**
|
||||||
|
* Maps map names to the real maps.
|
||||||
|
*/
|
||||||
private ObjectMap<String, Map> maps = new ObjectMap<>();
|
private ObjectMap<String, Map> maps = new ObjectMap<>();
|
||||||
/**All maps stored in an ordered array.*/
|
/**
|
||||||
|
* All maps stored in an ordered array.
|
||||||
|
*/
|
||||||
private Array<Map> allMaps = new ThreadArray<>();
|
private Array<Map> allMaps = new ThreadArray<>();
|
||||||
/**Temporary array used for returning things.*/
|
/**
|
||||||
|
* Temporary array used for returning things.
|
||||||
|
*/
|
||||||
private Array<Map> returnArray = new ThreadArray<>();
|
private Array<Map> returnArray = new ThreadArray<>();
|
||||||
/**Used for storing a list of custom map names for GWT.*/
|
/**
|
||||||
|
* Used for storing a list of custom map names for GWT.
|
||||||
|
*/
|
||||||
private Array<String> customMapNames;
|
private Array<String> customMapNames;
|
||||||
|
|
||||||
public Maps(){
|
public Maps(){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a list of all maps, including custom ones.*/
|
/**
|
||||||
|
* Returns a list of all maps, including custom ones.
|
||||||
|
*/
|
||||||
public Array<Map> all(){
|
public Array<Map> all(){
|
||||||
return allMaps;
|
return allMaps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a list of only custom maps.*/
|
/**
|
||||||
|
* Returns a list of only custom maps.
|
||||||
|
*/
|
||||||
public Array<Map> customMaps(){
|
public Array<Map> customMaps(){
|
||||||
returnArray.clear();
|
returnArray.clear();
|
||||||
for(Map map : allMaps){
|
for(Map map : allMaps){
|
||||||
@@ -49,7 +65,9 @@ public class Maps implements Disposable{
|
|||||||
return returnArray;
|
return returnArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a list of only default maps.*/
|
/**
|
||||||
|
* Returns a list of only default maps.
|
||||||
|
*/
|
||||||
public Array<Map> defaultMaps(){
|
public Array<Map> defaultMaps(){
|
||||||
returnArray.clear();
|
returnArray.clear();
|
||||||
for(Map map : allMaps){
|
for(Map map : allMaps){
|
||||||
@@ -58,12 +76,16 @@ public class Maps implements Disposable{
|
|||||||
return returnArray;
|
return returnArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns map by internal name.*/
|
/**
|
||||||
|
* Returns map by internal name.
|
||||||
|
*/
|
||||||
public Map getByName(String name){
|
public Map getByName(String name){
|
||||||
return maps.get(name);
|
return maps.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Load all maps. Should be called at application start.*/
|
/**
|
||||||
|
* Load all maps. Should be called at application start.
|
||||||
|
*/
|
||||||
public void load(){
|
public void load(){
|
||||||
try{
|
try{
|
||||||
for(String name : defaultMapNames){
|
for(String name : defaultMapNames){
|
||||||
@@ -77,7 +99,9 @@ public class Maps implements Disposable{
|
|||||||
loadCustomMaps();
|
loadCustomMaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Save a map. This updates all values and stored data necessary.*/
|
/**
|
||||||
|
* Save a map. This updates all values and stored data necessary.
|
||||||
|
*/
|
||||||
public void saveMap(String name, MapTileData data, ObjectMap<String, String> tags){
|
public void saveMap(String name, MapTileData data, ObjectMap<String, String> tags){
|
||||||
try{
|
try{
|
||||||
if(!gwt){
|
if(!gwt){
|
||||||
@@ -114,7 +138,9 @@ public class Maps implements Disposable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Removes a map completely.*/
|
/**
|
||||||
|
* Removes a map completely.
|
||||||
|
*/
|
||||||
public void removeMap(Map map){
|
public void removeMap(Map map){
|
||||||
if(map.texture != null){
|
if(map.texture != null){
|
||||||
map.texture.dispose();
|
map.texture.dispose();
|
||||||
@@ -177,7 +203,9 @@ public class Maps implements Disposable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns an input stream supplier for a given map name.*/
|
/**
|
||||||
|
* Returns an input stream supplier for a given map name.
|
||||||
|
*/
|
||||||
private Supplier<InputStream> getStreamFor(String name){
|
private Supplier<InputStream> getStreamFor(String name){
|
||||||
if(!gwt){
|
if(!gwt){
|
||||||
return customMapDirectory.child(name + "." + mapExtension)::read;
|
return customMapDirectory.child(name + "." + mapExtension)::read;
|
||||||
|
|||||||
@@ -23,5 +23,6 @@ public abstract class SaveFileVersion {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract void read(DataInputStream stream) throws IOException;
|
public abstract void read(DataInputStream stream) throws IOException;
|
||||||
|
|
||||||
public abstract void write(DataOutputStream stream) throws IOException;
|
public abstract void write(DataOutputStream stream) throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,9 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
/**Class for specifying read/write methods for code generation.*/
|
/**
|
||||||
|
* Class for specifying read/write methods for code generation.
|
||||||
|
*/
|
||||||
public class TypeIO{
|
public class TypeIO{
|
||||||
|
|
||||||
@WriteClass(Player.class)
|
@WriteClass(Player.class)
|
||||||
|
|||||||
@@ -19,11 +19,17 @@ public class Administration {
|
|||||||
public static final int defaultMaxBrokenBlocks = 15;
|
public static final int defaultMaxBrokenBlocks = 15;
|
||||||
public static final int defaultBreakCooldown = 1000 * 15;
|
public static final int defaultBreakCooldown = 1000 * 15;
|
||||||
|
|
||||||
/**All player info. Maps UUIDs to info. This persists throughout restarts.*/
|
/**
|
||||||
|
* All player info. Maps UUIDs to info. This persists throughout restarts.
|
||||||
|
*/
|
||||||
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
|
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
|
||||||
/**Maps UUIDs to trace infos. This is wiped when a player logs off.*/
|
/**
|
||||||
|
* Maps UUIDs to trace infos. This is wiped when a player logs off.
|
||||||
|
*/
|
||||||
private ObjectMap<String, TraceInfo> traceInfo = new ObjectMap<>();
|
private ObjectMap<String, TraceInfo> traceInfo = new ObjectMap<>();
|
||||||
/**Maps packed coordinates to logs for that coordinate */
|
/**
|
||||||
|
* Maps packed coordinates to logs for that coordinate
|
||||||
|
*/
|
||||||
private IntMap<Array<EditLog>> editLogs = new IntMap<>();
|
private IntMap<Array<EditLog>> editLogs = new IntMap<>();
|
||||||
|
|
||||||
private Array<String> bannedIPs = new Array<>();
|
private Array<String> bannedIPs = new Array<>();
|
||||||
@@ -42,6 +48,11 @@ public class Administration {
|
|||||||
return Settings.getBool("antigrief");
|
return Settings.getBool("antigrief");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAntiGrief(boolean antiGrief){
|
||||||
|
Settings.putBool("antigrief", antiGrief);
|
||||||
|
Settings.save();
|
||||||
|
}
|
||||||
|
|
||||||
public boolean allowsCustomClients(){
|
public boolean allowsCustomClients(){
|
||||||
return Settings.getBool("allow-custom", !headless);
|
return Settings.getBool("allow-custom", !headless);
|
||||||
}
|
}
|
||||||
@@ -55,11 +66,6 @@ public class Administration {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAntiGrief(boolean antiGrief){
|
|
||||||
Settings.putBool("antigrief", antiGrief);
|
|
||||||
Settings.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAntiGriefParams(int maxBreak, int cooldown){
|
public void setAntiGriefParams(int maxBreak, int cooldown){
|
||||||
Settings.putInt("antigrief-max", maxBreak);
|
Settings.putInt("antigrief-max", maxBreak);
|
||||||
Settings.putInt("antigrief-cooldown", cooldown);
|
Settings.putInt("antigrief-cooldown", cooldown);
|
||||||
@@ -71,11 +77,11 @@ public class Administration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void logEdit(int x, int y, Player player, Block block, int rotation, EditLog.EditAction action){
|
public void logEdit(int x, int y, Player player, Block block, int rotation, EditLog.EditAction action){
|
||||||
if(block instanceof BlockPart || block instanceof Rock || block instanceof Floor || block instanceof StaticBlock) return;
|
if(block instanceof BlockPart || block instanceof Rock || block instanceof Floor || block instanceof StaticBlock)
|
||||||
|
return;
|
||||||
if(editLogs.containsKey(x + y * world.width())){
|
if(editLogs.containsKey(x + y * world.width())){
|
||||||
editLogs.get(x + y * world.width()).add(new EditLog(player.name, block, rotation, action));
|
editLogs.get(x + y * world.width()).add(new EditLog(player.name, block, rotation, action));
|
||||||
}
|
}else{
|
||||||
else {
|
|
||||||
Array<EditLog> logs = new Array<>();
|
Array<EditLog> logs = new Array<>();
|
||||||
logs.add(new EditLog(player.name, block, rotation, action));
|
logs.add(new EditLog(player.name, block, rotation, action));
|
||||||
editLogs.put(x + y * world.width(), logs);
|
editLogs.put(x + y * world.width(), logs);
|
||||||
@@ -167,7 +173,9 @@ public class Administration {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Call when a player joins to update their information here.*/
|
/**
|
||||||
|
* Call when a player joins to update their information here.
|
||||||
|
*/
|
||||||
public void updatePlayerJoined(String id, String ip, String name){
|
public void updatePlayerJoined(String id, String ip, String name){
|
||||||
PlayerInfo info = getCreateInfo(id);
|
PlayerInfo info = getCreateInfo(id);
|
||||||
info.lastName = name;
|
info.lastName = name;
|
||||||
@@ -177,7 +185,9 @@ public class Administration {
|
|||||||
if(!info.ips.contains(ip, false)) info.ips.add(ip);
|
if(!info.ips.contains(ip, false)) info.ips.add(ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns trace info by IP.*/
|
/**
|
||||||
|
* Returns trace info by IP.
|
||||||
|
*/
|
||||||
public TraceInfo getTraceByID(String uuid){
|
public TraceInfo getTraceByID(String uuid){
|
||||||
if(!traceInfo.containsKey(uuid)) traceInfo.put(uuid, new TraceInfo(uuid));
|
if(!traceInfo.containsKey(uuid)) traceInfo.put(uuid, new TraceInfo(uuid));
|
||||||
|
|
||||||
@@ -188,8 +198,10 @@ public class Administration {
|
|||||||
traceInfo.clear();
|
traceInfo.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Bans a player by IP; returns whether this player was already banned.
|
/**
|
||||||
* If there are players who at any point had this IP, they will be UUID banned as well.*/
|
* Bans a player by IP; returns whether this player was already banned.
|
||||||
|
* If there are players who at any point had this IP, they will be UUID banned as well.
|
||||||
|
*/
|
||||||
public boolean banPlayerIP(String ip){
|
public boolean banPlayerIP(String ip){
|
||||||
if(bannedIPs.contains(ip, false))
|
if(bannedIPs.contains(ip, false))
|
||||||
return false;
|
return false;
|
||||||
@@ -206,7 +218,9 @@ public class Administration {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Bans a player by UUID; returns whether this player was already banned.*/
|
/**
|
||||||
|
* Bans a player by UUID; returns whether this player was already banned.
|
||||||
|
*/
|
||||||
public boolean banPlayerID(String id){
|
public boolean banPlayerID(String id){
|
||||||
if(playerInfo.containsKey(id) && playerInfo.get(id).banned)
|
if(playerInfo.containsKey(id) && playerInfo.get(id).banned)
|
||||||
return false;
|
return false;
|
||||||
@@ -218,8 +232,10 @@ public class Administration {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Unbans a player by IP; returns whether this player was banned in the first place.
|
/**
|
||||||
* This method also unbans any player that was banned and had this IP.*/
|
* Unbans a player by IP; returns whether this player was banned in the first place.
|
||||||
|
* This method also unbans any player that was banned and had this IP.
|
||||||
|
*/
|
||||||
public boolean unbanPlayerIP(String ip){
|
public boolean unbanPlayerIP(String ip){
|
||||||
boolean found = bannedIPs.contains(ip, false);
|
boolean found = bannedIPs.contains(ip, false);
|
||||||
|
|
||||||
@@ -237,8 +253,10 @@ public class Administration {
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Unbans a player by ID; returns whether this player was banned in the first place.
|
/**
|
||||||
* This also unbans all IPs the player used.*/
|
* Unbans a player by ID; returns whether this player was banned in the first place.
|
||||||
|
* This also unbans all IPs the player used.
|
||||||
|
*/
|
||||||
public boolean unbanPlayerID(String id){
|
public boolean unbanPlayerID(String id){
|
||||||
PlayerInfo info = getCreateInfo(id);
|
PlayerInfo info = getCreateInfo(id);
|
||||||
|
|
||||||
@@ -252,7 +270,9 @@ public class Administration {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns list of all players with admin status*/
|
/**
|
||||||
|
* Returns list of all players with admin status
|
||||||
|
*/
|
||||||
public Array<PlayerInfo> getAdmins(){
|
public Array<PlayerInfo> getAdmins(){
|
||||||
Array<PlayerInfo> result = new Array<>();
|
Array<PlayerInfo> result = new Array<>();
|
||||||
for(PlayerInfo info : playerInfo.values()){
|
for(PlayerInfo info : playerInfo.values()){
|
||||||
@@ -263,7 +283,9 @@ public class Administration {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns list of all players with admin status*/
|
/**
|
||||||
|
* Returns list of all players with admin status
|
||||||
|
*/
|
||||||
public Array<PlayerInfo> getBanned(){
|
public Array<PlayerInfo> getBanned(){
|
||||||
Array<PlayerInfo> result = new Array<>();
|
Array<PlayerInfo> result = new Array<>();
|
||||||
for(PlayerInfo info : playerInfo.values()){
|
for(PlayerInfo info : playerInfo.values()){
|
||||||
@@ -274,12 +296,16 @@ public class Administration {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns all banned IPs. This does not include the IPs of ID-banned players.*/
|
/**
|
||||||
|
* Returns all banned IPs. This does not include the IPs of ID-banned players.
|
||||||
|
*/
|
||||||
public Array<String> getBannedIPs(){
|
public Array<String> getBannedIPs(){
|
||||||
return bannedIPs;
|
return bannedIPs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Makes a player an admin. Returns whether this player was already an admin.*/
|
/**
|
||||||
|
* Makes a player an admin. Returns whether this player was already an admin.
|
||||||
|
*/
|
||||||
public boolean adminPlayer(String id, String usid){
|
public boolean adminPlayer(String id, String usid){
|
||||||
PlayerInfo info = getCreateInfo(id);
|
PlayerInfo info = getCreateInfo(id);
|
||||||
|
|
||||||
@@ -293,7 +319,9 @@ public class Administration {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Makes a player no longer an admin. Returns whether this player was an admin in the first place.*/
|
/**
|
||||||
|
* Makes a player no longer an admin. Returns whether this player was an admin in the first place.
|
||||||
|
*/
|
||||||
public boolean unAdminPlayer(String id){
|
public boolean unAdminPlayer(String id){
|
||||||
PlayerInfo info = getCreateInfo(id);
|
PlayerInfo info = getCreateInfo(id);
|
||||||
|
|
||||||
@@ -401,7 +429,8 @@ public class Administration {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
private PlayerInfo(){}
|
private PlayerInfo(){
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.anuke.mindustry.net;
|
package io.anuke.mindustry.net;
|
||||||
|
|
||||||
/**Stores class nameas for remote method invocation for consistency's sake.*/
|
/**
|
||||||
|
* Stores class nameas for remote method invocation for consistency's sake.
|
||||||
|
*/
|
||||||
public class In{
|
public class In{
|
||||||
public static final String normal = "Call";
|
public static final String normal = "Call";
|
||||||
public static final String entities = "CallEntity";
|
public static final String entities = "CallEntity";
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ public class Net{
|
|||||||
|
|
||||||
private static IntMap<StreamBuilder> streams = new IntMap<>();
|
private static IntMap<StreamBuilder> streams = new IntMap<>();
|
||||||
|
|
||||||
/**Display a network error.*/
|
/**
|
||||||
|
* Display a network error.
|
||||||
|
*/
|
||||||
public static void showError(String text){
|
public static void showError(String text){
|
||||||
if(!headless){
|
if(!headless){
|
||||||
ui.showError(text);
|
ui.showError(text);
|
||||||
@@ -47,7 +49,9 @@ public class Net{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sets the client loaded status, or whether it will recieve normal packets from the server.*/
|
/**
|
||||||
|
* Sets the client loaded status, or whether it will recieve normal packets from the server.
|
||||||
|
*/
|
||||||
public static void setClientLoaded(boolean loaded){
|
public static void setClientLoaded(boolean loaded){
|
||||||
clientLoaded = loaded;
|
clientLoaded = loaded;
|
||||||
|
|
||||||
@@ -62,7 +66,9 @@ public class Net{
|
|||||||
packetQueue.clear();
|
packetQueue.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Connect to an address.*/
|
/**
|
||||||
|
* Connect to an address.
|
||||||
|
*/
|
||||||
public static void connect(String ip, int port) throws IOException{
|
public static void connect(String ip, int port) throws IOException{
|
||||||
if(!active){
|
if(!active){
|
||||||
clientProvider.connect(ip, port);
|
clientProvider.connect(ip, port);
|
||||||
@@ -73,7 +79,9 @@ public class Net{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Host a server at an address*/
|
/**
|
||||||
|
* Host a server at an address
|
||||||
|
*/
|
||||||
public static void host(int port) throws IOException{
|
public static void host(int port) throws IOException{
|
||||||
serverProvider.host(port);
|
serverProvider.host(port);
|
||||||
active = true;
|
active = true;
|
||||||
@@ -82,7 +90,9 @@ public class Net{
|
|||||||
Timers.runTask(60f, Platform.instance::updateRPC);
|
Timers.runTask(60f, Platform.instance::updateRPC);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Closes the server.*/
|
/**
|
||||||
|
* Closes the server.
|
||||||
|
*/
|
||||||
public static void closeServer(){
|
public static void closeServer(){
|
||||||
serverProvider.close();
|
serverProvider.close();
|
||||||
server = false;
|
server = false;
|
||||||
@@ -95,23 +105,31 @@ public class Net{
|
|||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Starts discovering servers on a different thread. Does not work with GWT.
|
/**
|
||||||
* Callback is run on the main libGDX thread.*/
|
* Starts discovering servers on a different thread. Does not work with GWT.
|
||||||
|
* Callback is run on the main libGDX thread.
|
||||||
|
*/
|
||||||
public static void discoverServers(Consumer<Array<Host>> cons){
|
public static void discoverServers(Consumer<Array<Host>> cons){
|
||||||
clientProvider.discover(cons);
|
clientProvider.discover(cons);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a list of all connections IDs.*/
|
/**
|
||||||
|
* Returns a list of all connections IDs.
|
||||||
|
*/
|
||||||
public static Array<NetConnection> getConnections(){
|
public static Array<NetConnection> getConnections(){
|
||||||
return (Array<NetConnection>) serverProvider.getConnections();
|
return (Array<NetConnection>) serverProvider.getConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Returns a connection by ID*/
|
/**
|
||||||
|
* Returns a connection by ID
|
||||||
|
*/
|
||||||
public static NetConnection getConnection(int id){
|
public static NetConnection getConnection(int id){
|
||||||
return serverProvider.getByID(id);
|
return serverProvider.getByID(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Send an object to all connected clients, or to the server if this is a client.*/
|
/**
|
||||||
|
* Send an object to all connected clients, or to the server if this is a client.
|
||||||
|
*/
|
||||||
public static void send(Object object, SendMode mode){
|
public static void send(Object object, SendMode mode){
|
||||||
if(server){
|
if(server){
|
||||||
if(serverProvider != null) serverProvider.send(object, mode);
|
if(serverProvider != null) serverProvider.send(object, mode);
|
||||||
@@ -120,42 +138,58 @@ public class Net{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Send an object to a certain client. Server-side only*/
|
/**
|
||||||
|
* Send an object to a certain client. Server-side only
|
||||||
|
*/
|
||||||
public static void sendTo(int id, Object object, SendMode mode){
|
public static void sendTo(int id, Object object, SendMode mode){
|
||||||
serverProvider.sendTo(id, object, mode);
|
serverProvider.sendTo(id, object, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Send an object to everyone EXCEPT certain client. Server-side only*/
|
/**
|
||||||
|
* Send an object to everyone EXCEPT certain client. Server-side only
|
||||||
|
*/
|
||||||
public static void sendExcept(int id, Object object, SendMode mode){
|
public static void sendExcept(int id, Object object, SendMode mode){
|
||||||
serverProvider.sendExcept(id, object, mode);
|
serverProvider.sendExcept(id, object, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Send a stream to a specific client. Server-side only.*/
|
/**
|
||||||
|
* Send a stream to a specific client. Server-side only.
|
||||||
|
*/
|
||||||
public static void sendStream(int id, Streamable stream){
|
public static void sendStream(int id, Streamable stream){
|
||||||
serverProvider.sendStream(id, stream);
|
serverProvider.sendStream(id, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sets the net clientProvider, e.g. what handles sending, recieving and connecting to a server.*/
|
/**
|
||||||
|
* Sets the net clientProvider, e.g. what handles sending, recieving and connecting to a server.
|
||||||
|
*/
|
||||||
public static void setClientProvider(ClientProvider provider){
|
public static void setClientProvider(ClientProvider provider){
|
||||||
Net.clientProvider = provider;
|
Net.clientProvider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Sets the net serverProvider, e.g. what handles hosting a server.*/
|
/**
|
||||||
|
* Sets the net serverProvider, e.g. what handles hosting a server.
|
||||||
|
*/
|
||||||
public static void setServerProvider(ServerProvider provider){
|
public static void setServerProvider(ServerProvider provider){
|
||||||
Net.serverProvider = provider;
|
Net.serverProvider = provider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Registers a client listener for when an object is recieved.*/
|
/**
|
||||||
|
* Registers a client listener for when an object is recieved.
|
||||||
|
*/
|
||||||
public static <T> void handleClient(Class<T> type, Consumer<T> listener){
|
public static <T> void handleClient(Class<T> type, Consumer<T> listener){
|
||||||
clientListeners.put(type, listener);
|
clientListeners.put(type, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Registers a server listener for when an object is recieved.*/
|
/**
|
||||||
|
* Registers a server listener for when an object is recieved.
|
||||||
|
*/
|
||||||
public static <T> void handleServer(Class<T> type, BiConsumer<Integer, T> listener){
|
public static <T> void handleServer(Class<T> type, BiConsumer<Integer, T> listener){
|
||||||
serverListeners.put(type, (BiConsumer<Integer, Object>) listener);
|
serverListeners.put(type, (BiConsumer<Integer, Object>) listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Call to handle a packet being recieved for the client.*/
|
/**
|
||||||
|
* Call to handle a packet being recieved for the client.
|
||||||
|
*/
|
||||||
public static void handleClientReceived(Object object){
|
public static void handleClientReceived(Object object){
|
||||||
|
|
||||||
if(object instanceof StreamBegin){
|
if(object instanceof StreamBegin){
|
||||||
@@ -175,7 +209,8 @@ public class Net{
|
|||||||
}else if(clientListeners.get(object.getClass()) != null){
|
}else if(clientListeners.get(object.getClass()) != null){
|
||||||
|
|
||||||
if(clientLoaded || ((object instanceof Packet) && ((Packet) object).isImportant())){
|
if(clientLoaded || ((object instanceof Packet) && ((Packet) object).isImportant())){
|
||||||
if(clientListeners.get(object.getClass()) != null) clientListeners.get(object.getClass()).accept(object);
|
if(clientListeners.get(object.getClass()) != null)
|
||||||
|
clientListeners.get(object.getClass()).accept(object);
|
||||||
synchronized(packetPoolLock){
|
synchronized(packetPoolLock){
|
||||||
Pooling.free(object);
|
Pooling.free(object);
|
||||||
}
|
}
|
||||||
@@ -192,11 +227,14 @@ public class Net{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Call to handle a packet being recieved for the server.*/
|
/**
|
||||||
|
* Call to handle a packet being recieved for the server.
|
||||||
|
*/
|
||||||
public static void handleServerReceived(int connection, Object object){
|
public static void handleServerReceived(int connection, Object object){
|
||||||
|
|
||||||
if(serverListeners.get(object.getClass()) != null){
|
if(serverListeners.get(object.getClass()) != null){
|
||||||
if(serverListeners.get(object.getClass()) != null) serverListeners.get(object.getClass()).accept(connection, object);
|
if(serverListeners.get(object.getClass()) != null)
|
||||||
|
serverListeners.get(object.getClass()).accept(connection, object);
|
||||||
synchronized(packetPoolLock){
|
synchronized(packetPoolLock){
|
||||||
Pooling.free(object);
|
Pooling.free(object);
|
||||||
}
|
}
|
||||||
@@ -205,32 +243,44 @@ public class Net{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Pings a host in an new thread. If an error occured, failed() should be called with the exception. */
|
/**
|
||||||
|
* Pings a host in an new thread. If an error occured, failed() should be called with the exception.
|
||||||
|
*/
|
||||||
public static void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed){
|
public static void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed){
|
||||||
clientProvider.pingHost(address, port, valid, failed);
|
clientProvider.pingHost(address, port, valid, failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Update client ping.*/
|
/**
|
||||||
|
* Update client ping.
|
||||||
|
*/
|
||||||
public static void updatePing(){
|
public static void updatePing(){
|
||||||
clientProvider.updatePing();
|
clientProvider.updatePing();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Get the client ping. Only valid after updatePing().*/
|
/**
|
||||||
|
* Get the client ping. Only valid after updatePing().
|
||||||
|
*/
|
||||||
public static int getPing(){
|
public static int getPing(){
|
||||||
return server() ? 0 : clientProvider.getPing();
|
return server() ? 0 : clientProvider.getPing();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Whether the net is active, e.g. whether this is a multiplayer game.*/
|
/**
|
||||||
|
* Whether the net is active, e.g. whether this is a multiplayer game.
|
||||||
|
*/
|
||||||
public static boolean active(){
|
public static boolean active(){
|
||||||
return active;
|
return active;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Whether this is a server or not.*/
|
/**
|
||||||
|
* Whether this is a server or not.
|
||||||
|
*/
|
||||||
public static boolean server(){
|
public static boolean server(){
|
||||||
return server && active;
|
return server && active;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Whether this is a client or not.*/
|
/**
|
||||||
|
* Whether this is a client or not.
|
||||||
|
*/
|
||||||
public static boolean client(){
|
public static boolean client(){
|
||||||
return !server && active;
|
return !server && active;
|
||||||
}
|
}
|
||||||
@@ -260,54 +310,108 @@ public class Net{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cancelled() {}
|
public void cancelled(){
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Client implementation.*/
|
|
||||||
public interface ClientProvider {
|
|
||||||
/**Connect to a server.*/
|
|
||||||
void connect(String ip, int port) throws IOException;
|
|
||||||
/**Send an object to the server.*/
|
|
||||||
void send(Object object, SendMode mode);
|
|
||||||
/**Update the ping. Should be done every second or so.*/
|
|
||||||
void updatePing();
|
|
||||||
/**Get ping in milliseconds. Will only be valid after a call to updatePing.*/
|
|
||||||
int getPing();
|
|
||||||
/**Disconnect from the server.*/
|
|
||||||
void disconnect();
|
|
||||||
/**Discover servers. This should run the callback regardless of whether any servers are found. Should not block.
|
|
||||||
* Callback should be run on libGDX main thread.*/
|
|
||||||
void discover(Consumer<Array<Host>> callback);
|
|
||||||
/**Ping a host. If an error occured, failed() should be called with the exception. */
|
|
||||||
void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed);
|
|
||||||
/**Close all connections.*/
|
|
||||||
void dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Server implementation.*/
|
|
||||||
public interface ServerProvider {
|
|
||||||
/**Host a server at specified port.*/
|
|
||||||
void host(int port) throws IOException;
|
|
||||||
/**Sends a large stream of data to a specific client.*/
|
|
||||||
void sendStream(int id, Streamable stream);
|
|
||||||
/**Send an object to everyone connected.*/
|
|
||||||
void send(Object object, SendMode mode);
|
|
||||||
/**Send an object to a specific client ID.*/
|
|
||||||
void sendTo(int id, Object object, SendMode mode);
|
|
||||||
/**Send an object to everyone <i>except</i> a client ID.*/
|
|
||||||
void sendExcept(int id, Object object, SendMode mode);
|
|
||||||
/**Close the server connection.*/
|
|
||||||
void close();
|
|
||||||
/**Return all connected users.*/
|
|
||||||
Array<? extends NetConnection> getConnections();
|
|
||||||
/**Returns a connection by ID.*/
|
|
||||||
NetConnection getByID(int id);
|
|
||||||
/**Close all connections.*/
|
|
||||||
void dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum SendMode{
|
public enum SendMode{
|
||||||
tcp, udp
|
tcp, udp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Client implementation.
|
||||||
|
*/
|
||||||
|
public interface ClientProvider{
|
||||||
|
/**
|
||||||
|
* Connect to a server.
|
||||||
|
*/
|
||||||
|
void connect(String ip, int port) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an object to the server.
|
||||||
|
*/
|
||||||
|
void send(Object object, SendMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the ping. Should be done every second or so.
|
||||||
|
*/
|
||||||
|
void updatePing();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get ping in milliseconds. Will only be valid after a call to updatePing.
|
||||||
|
*/
|
||||||
|
int getPing();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect from the server.
|
||||||
|
*/
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Discover servers. This should run the callback regardless of whether any servers are found. Should not block.
|
||||||
|
* Callback should be run on libGDX main thread.
|
||||||
|
*/
|
||||||
|
void discover(Consumer<Array<Host>> callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ping a host. If an error occured, failed() should be called with the exception.
|
||||||
|
*/
|
||||||
|
void pingHost(String address, int port, Consumer<Host> valid, Consumer<Exception> failed);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close all connections.
|
||||||
|
*/
|
||||||
|
void dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server implementation.
|
||||||
|
*/
|
||||||
|
public interface ServerProvider{
|
||||||
|
/**
|
||||||
|
* Host a server at specified port.
|
||||||
|
*/
|
||||||
|
void host(int port) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends a large stream of data to a specific client.
|
||||||
|
*/
|
||||||
|
void sendStream(int id, Streamable stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an object to everyone connected.
|
||||||
|
*/
|
||||||
|
void send(Object object, SendMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an object to a specific client ID.
|
||||||
|
*/
|
||||||
|
void sendTo(int id, Object object, SendMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send an object to everyone <i>except</i> a client ID.
|
||||||
|
*/
|
||||||
|
void sendExcept(int id, Object object, SendMode mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the server connection.
|
||||||
|
*/
|
||||||
|
void close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all connected users.
|
||||||
|
*/
|
||||||
|
Array<? extends NetConnection> getConnections();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a connection by ID.
|
||||||
|
*/
|
||||||
|
NetConnection getByID(int id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close all connections.
|
||||||
|
*/
|
||||||
|
void dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,14 @@ public abstract class NetConnection {
|
|||||||
public final int id;
|
public final int id;
|
||||||
public final String address;
|
public final String address;
|
||||||
|
|
||||||
/**The current base snapshot that the client is absolutely confirmed to have recieved.
|
/**
|
||||||
* All sent snapshots should be taking the diff from this base snapshot, if it isn't null.*/
|
* The current base snapshot that the client is absolutely confirmed to have recieved.
|
||||||
|
* All sent snapshots should be taking the diff from this base snapshot, if it isn't null.
|
||||||
|
*/
|
||||||
public byte[] currentBaseSnapshot;
|
public byte[] currentBaseSnapshot;
|
||||||
/**ID of the current base snapshot.*/
|
/**
|
||||||
|
* ID of the current base snapshot.
|
||||||
|
*/
|
||||||
public int currentBaseID = -1;
|
public int currentBaseID = -1;
|
||||||
|
|
||||||
public int lastSentBase = -1;
|
public int lastSentBase = -1;
|
||||||
@@ -17,9 +21,13 @@ public abstract class NetConnection {
|
|||||||
public byte[] lastSentRawSnapshot;
|
public byte[] lastSentRawSnapshot;
|
||||||
public int lastSentSnapshotID = -1;
|
public int lastSentSnapshotID = -1;
|
||||||
|
|
||||||
/**ID of last recieved client snapshot.*/
|
/**
|
||||||
|
* ID of last recieved client snapshot.
|
||||||
|
*/
|
||||||
public int lastRecievedClientSnapshot = -1;
|
public int lastRecievedClientSnapshot = -1;
|
||||||
/**Timestamp of last recieved snapshot.*/
|
/**
|
||||||
|
* Timestamp of last recieved snapshot.
|
||||||
|
*/
|
||||||
public long lastRecievedClientTime;
|
public long lastRecievedClientTime;
|
||||||
|
|
||||||
public boolean hasConnected = false;
|
public boolean hasConnected = false;
|
||||||
@@ -34,5 +42,6 @@ public abstract class NetConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract void send(Object object, SendMode mode);
|
public abstract void send(Object object, SendMode mode);
|
||||||
|
|
||||||
public abstract void close();
|
public abstract void close();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,7 +112,9 @@ public class NetworkIO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Return whether a custom map is expected, and thus whether the client should wait for additional data.*/
|
/**
|
||||||
|
* Return whether a custom map is expected, and thus whether the client should wait for additional data.
|
||||||
|
*/
|
||||||
public static void loadWorld(InputStream is){
|
public static void loadWorld(InputStream is){
|
||||||
|
|
||||||
Player player = players[0];
|
Player player = players[0];
|
||||||
|
|||||||
@@ -5,10 +5,14 @@ import com.badlogic.gdx.utils.Pool.Poolable;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
public interface Packet extends Poolable{
|
public interface Packet extends Poolable{
|
||||||
default void read(ByteBuffer buffer){}
|
default void read(ByteBuffer buffer){
|
||||||
default void write(ByteBuffer buffer){}
|
}
|
||||||
|
|
||||||
default void reset() {}
|
default void write(ByteBuffer buffer){
|
||||||
|
}
|
||||||
|
|
||||||
|
default void reset(){
|
||||||
|
}
|
||||||
|
|
||||||
default boolean isImportant(){
|
default boolean isImportant(){
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user