Autogenerated interpolation
This commit is contained in:
@@ -17,7 +17,15 @@ public class Annotations{
|
|||||||
public @interface Final{
|
public @interface Final{
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Indicates that a component field is imported from other components. */
|
/** Indicates that a field will be interpolated when synced. */
|
||||||
|
@Target({ElementType.FIELD})
|
||||||
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
|
public @interface SyncField{
|
||||||
|
/** If true, the field will be linearly interpolated. If false, it will be interpolated as an angle. */
|
||||||
|
boolean value();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates that a component field is imported from other components. This means it doesn't actually exist. */
|
||||||
@Target({ElementType.FIELD})
|
@Target({ElementType.FIELD})
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
public @interface Import{
|
public @interface Import{
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package mindustry.annotations.entity;
|
package mindustry.annotations.entity;
|
||||||
|
|
||||||
import arc.files.*;
|
import arc.files.*;
|
||||||
|
import arc.math.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
import arc.util.serialization.*;
|
import arc.util.serialization.*;
|
||||||
import com.squareup.javapoet.*;
|
import com.squareup.javapoet.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.annotations.*;
|
import mindustry.annotations.*;
|
||||||
|
import mindustry.annotations.util.*;
|
||||||
import mindustry.annotations.util.TypeIOResolver.*;
|
import mindustry.annotations.util.TypeIOResolver.*;
|
||||||
|
|
||||||
import javax.lang.model.element.*;
|
import javax.lang.model.element.*;
|
||||||
@@ -15,6 +17,8 @@ import static mindustry.annotations.BaseProcessor.instanceOf;
|
|||||||
|
|
||||||
public class EntityIO{
|
public class EntityIO{
|
||||||
final static Json json = new Json();
|
final static Json json = new Json();
|
||||||
|
//suffixes for sync fields
|
||||||
|
final static String targetSuf = "_TARGET_", lastSuf = "_LAST_";
|
||||||
|
|
||||||
final ClassSerializer serializer;
|
final ClassSerializer serializer;
|
||||||
final String name;
|
final String name;
|
||||||
@@ -104,6 +108,83 @@ public class EntityIO{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void writeSync(MethodSpec.Builder method, boolean write, Array<Svar> syncFields) throws Exception{
|
||||||
|
this.method = method;
|
||||||
|
this.write = write;
|
||||||
|
|
||||||
|
if(write){
|
||||||
|
//write uses most recent revision
|
||||||
|
for(RevisionField field : revisions.peek().fields){
|
||||||
|
io(field.type, "this." + field.name);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
Revision rev = revisions.peek();
|
||||||
|
|
||||||
|
//base read code
|
||||||
|
st("if(lastUpdated != 0) updateSpacing = $T.timeSinceMillis(lastUpdated)", Time.class);
|
||||||
|
st("lastUpdated = $T.millis()", Time.class);
|
||||||
|
|
||||||
|
//add code for reading revision
|
||||||
|
for(RevisionField field : rev.fields){
|
||||||
|
Svar sf = syncFields.find(s -> s.name().equals(field.name));
|
||||||
|
if(sf != null){
|
||||||
|
st(field.name + lastSuf + " = this." + field.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
io(field.type, "this." + (sf != null ? field.name + targetSuf : field.name) + " = ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeSyncManual(MethodSpec.Builder method, boolean write, Array<Svar> syncFields) throws Exception{
|
||||||
|
this.method = method;
|
||||||
|
this.write = write;
|
||||||
|
|
||||||
|
if(write){
|
||||||
|
for(Svar field : syncFields){
|
||||||
|
st("buffer.put(this.$L)", field.name());
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
//base read code
|
||||||
|
st("if(lastUpdated != 0) updateSpacing = $T.timeSinceMillis(lastUpdated)", Time.class);
|
||||||
|
st("lastUpdated = $T.millis()", Time.class);
|
||||||
|
|
||||||
|
//just read the field
|
||||||
|
for(Svar field : syncFields){
|
||||||
|
//last
|
||||||
|
st("this.$L = this.$L", field.name() + lastSuf, field.name());
|
||||||
|
//assign target
|
||||||
|
st("this.$L = buffer.get()", field.name() + targetSuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeInterpolate(MethodSpec.Builder method, Array<Svar> fields) throws Exception{
|
||||||
|
this.method = method;
|
||||||
|
|
||||||
|
cont("if(lastUpdated != 0 && updateSpacing != 0)");
|
||||||
|
|
||||||
|
//base calculations
|
||||||
|
st("float timeSinceUpdate = Time.timeSinceMillis(lastUpdated)");
|
||||||
|
st("float alpha = Math.min(timeSinceUpdate / updateSpacing, 2f)");
|
||||||
|
|
||||||
|
//write interpolated data, using slerp / lerp
|
||||||
|
for(Svar field : fields){
|
||||||
|
String name = field.name(), targetName = name + targetSuf, lastName = name + lastSuf;
|
||||||
|
st("$L = $T.$L($L, $L, alpha)", name, Mathf.class, field.annotation(SyncField.class).value() ? "lerp" : "slerp", lastName, targetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
ncont("else"); //no meaningful data has arrived yet
|
||||||
|
|
||||||
|
//write values directly to targets
|
||||||
|
for(Svar field : fields){
|
||||||
|
String name = field.name(), targetName = name + targetSuf;
|
||||||
|
st("$L = $L", name, targetName);
|
||||||
|
}
|
||||||
|
|
||||||
|
econt();
|
||||||
|
}
|
||||||
|
|
||||||
private void io(String type, String field) throws Exception{
|
private void io(String type, String field) throws Exception{
|
||||||
if(BaseProcessor.isPrimitive(type)){
|
if(BaseProcessor.isPrimitive(type)){
|
||||||
s(type.equals("boolean") ? "bool" : type.charAt(0) + "", field);
|
s(type.equals("boolean") ? "bool" : type.charAt(0) + "", field);
|
||||||
|
|||||||
@@ -218,10 +218,13 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
//add serialize() boolean
|
//add serialize() boolean
|
||||||
builder.addMethod(MethodSpec.methodBuilder("serialize").addModifiers(Modifier.PUBLIC, Modifier.FINAL).returns(boolean.class).addStatement("return " + ann.serialize()).build());
|
builder.addMethod(MethodSpec.methodBuilder("serialize").addModifiers(Modifier.PUBLIC, Modifier.FINAL).returns(boolean.class).addStatement("return " + ann.serialize()).build());
|
||||||
|
|
||||||
|
//all SyncField fields
|
||||||
|
Array<Svar> syncedFields = new Array<>();
|
||||||
|
|
||||||
//add all components
|
//add all components
|
||||||
for(Stype comp : components){
|
for(Stype comp : components){
|
||||||
|
|
||||||
//write fields to the class; ignoring transient ones
|
//write fields to the class; ignoring transient/imported ones
|
||||||
Array<Svar> fields = comp.fields().select(f -> !f.has(Import.class));
|
Array<Svar> fields = comp.fields().select(f -> !f.has(Import.class));
|
||||||
for(Svar f : fields){
|
for(Svar f : fields){
|
||||||
if(!usedFields.add(f.name())){
|
if(!usedFields.add(f.name())){
|
||||||
@@ -239,6 +242,7 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
if(f.is(Modifier.TRANSIENT)){
|
if(f.is(Modifier.TRANSIENT)){
|
||||||
fbuilder.addModifiers(Modifier.TRANSIENT);
|
fbuilder.addModifiers(Modifier.TRANSIENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
//add initializer if it exists
|
//add initializer if it exists
|
||||||
if(varInitializers.containsKey(f)){
|
if(varInitializers.containsKey(f)){
|
||||||
fbuilder.initializer(varInitializers.get(f));
|
fbuilder.initializer(varInitializers.get(f));
|
||||||
@@ -248,6 +252,24 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
fbuilder.addAnnotations(f.annotations().map(AnnotationSpec::get));
|
fbuilder.addAnnotations(f.annotations().map(AnnotationSpec::get));
|
||||||
builder.addField(fbuilder.build());
|
builder.addField(fbuilder.build());
|
||||||
specVariables.put(builder.fieldSpecs.get(builder.fieldSpecs.size() - 1), f);
|
specVariables.put(builder.fieldSpecs.get(builder.fieldSpecs.size() - 1), f);
|
||||||
|
|
||||||
|
//add extra sync fields
|
||||||
|
if(f.has(SyncField.class)){
|
||||||
|
if(!f.tname().toString().equals("float")) err("All SyncFields must be of type float", f);
|
||||||
|
|
||||||
|
syncedFields.add(f);
|
||||||
|
|
||||||
|
//a synced field has 3 values:
|
||||||
|
//- target state
|
||||||
|
//- last state
|
||||||
|
//- current state (the field itself, will be written to)
|
||||||
|
|
||||||
|
//target
|
||||||
|
builder.addField(FieldSpec.builder(float.class, f.name() + EntityIO.targetSuf).addModifiers(Modifier.TRANSIENT, Modifier.PRIVATE).build());
|
||||||
|
|
||||||
|
//last
|
||||||
|
builder.addField(FieldSpec.builder(float.class, f.name() + EntityIO.lastSuf).addModifiers(Modifier.TRANSIENT, Modifier.PRIVATE).build());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//get all utility methods from components
|
//get all utility methods from components
|
||||||
@@ -256,6 +278,8 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
syncedFields.sortComparing(Selement::name);
|
||||||
|
|
||||||
//override toString method
|
//override toString method
|
||||||
builder.addMethod(MethodSpec.methodBuilder("toString")
|
builder.addMethod(MethodSpec.methodBuilder("toString")
|
||||||
.addAnnotation(Override.class)
|
.addAnnotation(Override.class)
|
||||||
@@ -264,6 +288,7 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
.addStatement("return $S + $L", name + "#", "id").build());
|
.addStatement("return $S + $L", name + "#", "id").build());
|
||||||
|
|
||||||
EntityIO io = ann.serialize() ? new EntityIO(type.name(), builder, serializer, rootDirectory.child("annotations/src/main/resources/revisions").child(name)) : null;
|
EntityIO io = ann.serialize() ? new EntityIO(type.name(), builder, serializer, rootDirectory.child("annotations/src/main/resources/revisions").child(name)) : null;
|
||||||
|
boolean hasIO = ann.genio() && ann.serialize();
|
||||||
|
|
||||||
//add all methods from components
|
//add all methods from components
|
||||||
for(ObjectMap.Entry<String, Array<Smethod>> entry : methods){
|
for(ObjectMap.Entry<String, Array<Smethod>> entry : methods){
|
||||||
@@ -322,12 +347,40 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(io != null){
|
||||||
//SPECIAL CASE: I/O code
|
//SPECIAL CASE: I/O code
|
||||||
//note that serialization is generated even for non-serializing entities for manual usage
|
//note that serialization is generated even for non-serializing entities for manual usage
|
||||||
if((first.name().equals("read") || first.name().equals("write")) && ann.genio() && ann.serialize()){
|
if((first.name().equals("read") || first.name().equals("write")) && hasIO){
|
||||||
io.write(mbuilder, first.name().equals("write"));
|
io.write(mbuilder, first.name().equals("write"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//SPECIAL CASE: sync I/O code
|
||||||
|
if((first.name().equals("readSync") || first.name().equals("writeSync")) && hasIO){
|
||||||
|
io.writeSync(mbuilder, first.name().equals("writeSync"), syncedFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
//SPECIAL CASE: sync I/O code for writing to/from a manual buffer
|
||||||
|
if((first.name().equals("readSyncManual") || first.name().equals("writeSyncManual")) && hasIO){
|
||||||
|
io.writeSyncManual(mbuilder, first.name().equals("writeSyncManual"), syncedFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
//SPECIAL CASE: interpolate method implementation
|
||||||
|
if(first.name().equals("interpolate")){
|
||||||
|
io.writeInterpolate(mbuilder, syncedFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
//snap to target position
|
||||||
|
if(first.name().equals("snapSync")){
|
||||||
|
mbuilder.addStatement("updateSpacing = 16");
|
||||||
|
mbuilder.addStatement("lastUpdated = $T.millis()", Time.class);
|
||||||
|
for(Svar field : syncedFields){
|
||||||
|
//reset last+current state to target position
|
||||||
|
mbuilder.addStatement("$L = $L", field.name() + EntityIO.lastSuf, field.name() + EntityIO.targetSuf);
|
||||||
|
mbuilder.addStatement("$L = $L", field.name(), field.name() + EntityIO.targetSuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(Smethod elem : entry.value){
|
for(Smethod elem : entry.value){
|
||||||
if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE) || !methodBlocks.containsKey(elem)) continue;
|
if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE) || !methodBlocks.containsKey(elem)) continue;
|
||||||
|
|
||||||
@@ -373,12 +426,12 @@ public class EntityProcess extends BaseProcessor{
|
|||||||
//implement reset()
|
//implement reset()
|
||||||
MethodSpec.Builder resetBuilder = MethodSpec.methodBuilder("reset").addModifiers(Modifier.PUBLIC);
|
MethodSpec.Builder resetBuilder = MethodSpec.methodBuilder("reset").addModifiers(Modifier.PUBLIC);
|
||||||
for(FieldSpec spec : builder.fieldSpecs){
|
for(FieldSpec spec : builder.fieldSpecs){
|
||||||
Svar variable = specVariables.get(spec);
|
@Nullable Svar variable = specVariables.get(spec);
|
||||||
if(variable.isAny(Modifier.STATIC, Modifier.FINAL)) continue;
|
if(variable != null && variable.isAny(Modifier.STATIC, Modifier.FINAL)) continue;
|
||||||
|
|
||||||
if(spec.type.isPrimitive()){
|
if(spec.type.isPrimitive()){
|
||||||
//set to primitive default
|
//set to primitive default
|
||||||
resetBuilder.addStatement("$L = $L", spec.name, varInitializers.containsKey(variable) ? varInitializers.get(variable) : getDefault(spec.type.toString()));
|
resetBuilder.addStatement("$L = $L", spec.name, variable != null && varInitializers.containsKey(variable) ? varInitializers.get(variable) : getDefault(spec.type.toString()));
|
||||||
}else{
|
}else{
|
||||||
//set to default null
|
//set to default null
|
||||||
if(!varInitializers.containsKey(variable)){
|
if(!varInitializers.containsKey(variable)){
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
#Maps entity names to IDs. Autogenerated.
|
#Maps entity names to IDs. Autogenerated.
|
||||||
|
|
||||||
alpha=14
|
alpha=0
|
||||||
dart=15
|
block=1
|
||||||
draug=0
|
draug=2
|
||||||
mindustry.entities.comp.BulletComp=1
|
mindustry.entities.comp.BulletComp=3
|
||||||
mindustry.entities.comp.DecalComp=2
|
mindustry.entities.comp.DecalComp=4
|
||||||
mindustry.entities.comp.EffectComp=3
|
mindustry.entities.comp.EffectComp=5
|
||||||
mindustry.entities.comp.FireComp=4
|
mindustry.entities.comp.FireComp=6
|
||||||
mindustry.entities.comp.PlayerComp=5
|
mindustry.entities.comp.PlayerComp=7
|
||||||
mindustry.entities.comp.PuddleComp=6
|
mindustry.entities.comp.PuddleComp=8
|
||||||
mindustry.entities.comp.TileComp=7
|
mindustry.entities.comp.TileComp=9
|
||||||
mindustry.type.Weather.WeatherComp=8
|
mindustry.type.Weather.WeatherComp=10
|
||||||
mindustry.world.blocks.storage.LaunchPad.LaunchPayloadComp=9
|
mindustry.world.blocks.storage.LaunchPad.LaunchPayloadComp=11
|
||||||
oculon=16
|
oculon=12
|
||||||
phantom=10
|
phantom=13
|
||||||
titan=11
|
titan=14
|
||||||
vanguard=12
|
vanguard=15
|
||||||
wraith=13
|
wraith=16
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
{fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:tile,type:Tilec,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
||||||
@@ -1 +1 @@
|
|||||||
{fields:[{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:requests,type:arc.struct.Queue<mindustry.entities.units.BuildRequest>,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
{fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:requests,type:arc.struct.Queue<mindustry.entities.units.BuildRequest>,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:1,fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:requests,type:arc.struct.Queue<mindustry.entities.units.BuildRequest>,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:2,fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:requests,type:arc.struct.Queue<mindustry.entities.units.BuildRequest>,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +1 @@
|
|||||||
{fields:[{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
{fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:1,fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:2,fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +1 @@
|
|||||||
{fields:[{name:baseRotation,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
{fields:[{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:1,fields:[{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:2,fields:[{name:armor,type:float,size:4},{name:baseRotation,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +1 @@
|
|||||||
{fields:[{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
{fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:1,fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:2,fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:mineTile,type:mindustry.world.Tile,size:-1},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +1 @@
|
|||||||
{fields:[{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
{fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:1,fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{version:2,fields:[{name:armor,type:float,size:4},{name:elevation,type:float,size:4},{name:health,type:float,size:4},{name:rotation,type:float,size:4},{name:shield,type:float,size:4},{name:spawnedByCore,type:boolean,size:1},{name:stack,type:mindustry.type.ItemStack,size:-1},{name:statuses,type:arc.struct.Array<mindustry.entities.units.StatusEntry>,size:-1},{name:team,type:mindustry.game.Team,size:-1},{name:type,type:mindustry.type.UnitType,size:-1},{name:vel,type:arc.math.geom.Vec2,size:-1},{name:x,type:float,size:4},{name:y,type:float,size:4}]}
|
|
||||||
@@ -48,7 +48,6 @@ public class UnitTypes implements ContentList{
|
|||||||
dagger = new UnitType("dagger"){{
|
dagger = new UnitType("dagger"){{
|
||||||
speed = 0.5f;
|
speed = 0.5f;
|
||||||
hitsize = 8f;
|
hitsize = 8f;
|
||||||
mass = 1.75f;
|
|
||||||
health = 130;
|
health = 130;
|
||||||
weapons.add(new Weapon("large-weapon"){{
|
weapons.add(new Weapon("large-weapon"){{
|
||||||
reload = 14f;
|
reload = 14f;
|
||||||
@@ -64,7 +63,6 @@ public class UnitTypes implements ContentList{
|
|||||||
tier = 2;
|
tier = 2;
|
||||||
|
|
||||||
speed = 0.4f;
|
speed = 0.4f;
|
||||||
mass = 3.5f;
|
|
||||||
hitsize = 9f;
|
hitsize = 9f;
|
||||||
range = 10f;
|
range = 10f;
|
||||||
health = 460;
|
health = 460;
|
||||||
@@ -85,7 +83,6 @@ public class UnitTypes implements ContentList{
|
|||||||
crawler = new UnitType("crawler"){{
|
crawler = new UnitType("crawler"){{
|
||||||
speed = 0.65f;
|
speed = 0.65f;
|
||||||
hitsize = 8f;
|
hitsize = 8f;
|
||||||
mass = 1.75f;
|
|
||||||
health = 120;
|
health = 120;
|
||||||
sway = 0.25f;
|
sway = 0.25f;
|
||||||
weapons.add(new Weapon(){{
|
weapons.add(new Weapon(){{
|
||||||
@@ -160,7 +157,6 @@ public class UnitTypes implements ContentList{
|
|||||||
tier = 3;
|
tier = 3;
|
||||||
|
|
||||||
speed = 0.38f;
|
speed = 0.38f;
|
||||||
mass = 5f;
|
|
||||||
hitsize = 13f;
|
hitsize = 13f;
|
||||||
rotateSpeed = 3f;
|
rotateSpeed = 3f;
|
||||||
targetAir = false;
|
targetAir = false;
|
||||||
@@ -184,7 +180,6 @@ public class UnitTypes implements ContentList{
|
|||||||
|
|
||||||
speed = 0.4f;
|
speed = 0.4f;
|
||||||
drag = 0.4f;
|
drag = 0.4f;
|
||||||
mass = 5f;
|
|
||||||
hitsize = 10f;
|
hitsize = 10f;
|
||||||
rotateSpeed = 3f;
|
rotateSpeed = 3f;
|
||||||
targetAir = false;
|
targetAir = false;
|
||||||
@@ -206,7 +201,6 @@ public class UnitTypes implements ContentList{
|
|||||||
speed = 3f;
|
speed = 3f;
|
||||||
accel = 0.08f;
|
accel = 0.08f;
|
||||||
drag = 0.01f;
|
drag = 0.01f;
|
||||||
mass = 1.5f;
|
|
||||||
flying = true;
|
flying = true;
|
||||||
health = 75;
|
health = 75;
|
||||||
faceTarget = false;
|
faceTarget = false;
|
||||||
@@ -229,7 +223,6 @@ public class UnitTypes implements ContentList{
|
|||||||
|
|
||||||
health = 220;
|
health = 220;
|
||||||
speed = 2f;
|
speed = 2f;
|
||||||
mass = 3f;
|
|
||||||
accel = 0.08f;
|
accel = 0.08f;
|
||||||
drag = 0.016f;
|
drag = 0.016f;
|
||||||
flying = true;
|
flying = true;
|
||||||
@@ -255,7 +248,6 @@ public class UnitTypes implements ContentList{
|
|||||||
speed = 1.1f;
|
speed = 1.1f;
|
||||||
accel = 0.02f;
|
accel = 0.02f;
|
||||||
drag = 0.05f;
|
drag = 0.05f;
|
||||||
mass = 30f;
|
|
||||||
rotateSpeed = 0.5f;
|
rotateSpeed = 0.5f;
|
||||||
flying = true;
|
flying = true;
|
||||||
lowAltitude = true;
|
lowAltitude = true;
|
||||||
@@ -279,7 +271,6 @@ public class UnitTypes implements ContentList{
|
|||||||
speed = 1.3f;
|
speed = 1.3f;
|
||||||
drag = 0.1f;
|
drag = 0.1f;
|
||||||
hitsize = 8f;
|
hitsize = 8f;
|
||||||
mass = 1.75f;
|
|
||||||
health = 130;
|
health = 130;
|
||||||
immunities = ObjectSet.with(StatusEffects.wet);
|
immunities = ObjectSet.with(StatusEffects.wet);
|
||||||
weapons.add(new Weapon("mount-weapon"){{
|
weapons.add(new Weapon("mount-weapon"){{
|
||||||
@@ -331,7 +322,6 @@ public class UnitTypes implements ContentList{
|
|||||||
mineSpeed = 2f;
|
mineSpeed = 2f;
|
||||||
buildSpeed = 0.5f;
|
buildSpeed = 0.5f;
|
||||||
drag = 0.05f;
|
drag = 0.05f;
|
||||||
mass = 2f;
|
|
||||||
speed = 2.4f;
|
speed = 2.4f;
|
||||||
rotateSpeed = 15f;
|
rotateSpeed = 15f;
|
||||||
accel = 0.1f;
|
accel = 0.1f;
|
||||||
@@ -356,7 +346,6 @@ public class UnitTypes implements ContentList{
|
|||||||
phantom = new UnitType("phantom"){{
|
phantom = new UnitType("phantom"){{
|
||||||
flying = true;
|
flying = true;
|
||||||
drag = 0.05f;
|
drag = 0.05f;
|
||||||
mass = 2f;
|
|
||||||
speed = 3f;
|
speed = 3f;
|
||||||
rotateSpeed = 15f;
|
rotateSpeed = 15f;
|
||||||
accel = 0.3f;
|
accel = 0.3f;
|
||||||
@@ -374,10 +363,8 @@ public class UnitTypes implements ContentList{
|
|||||||
drillTier = -1;
|
drillTier = -1;
|
||||||
speed = 0.6f;
|
speed = 0.6f;
|
||||||
hitsize = 9f;
|
hitsize = 9f;
|
||||||
mass = 1.75f;
|
|
||||||
boostMultiplier = 2f;
|
boostMultiplier = 2f;
|
||||||
itemCapacity = 15;
|
itemCapacity = 15;
|
||||||
mass = 0.9f;
|
|
||||||
health = 160f;
|
health = 160f;
|
||||||
buildSpeed = 0.9f;
|
buildSpeed = 0.9f;
|
||||||
canBoost = true;
|
canBoost = true;
|
||||||
|
|||||||
@@ -399,11 +399,11 @@ public class NetClient implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
//read the entity
|
//read the entity
|
||||||
entity.read(Reads.get(input));
|
entity.readSync(Reads.get(input));
|
||||||
|
|
||||||
if(created && entity.interpolator().target != null){
|
if(created){
|
||||||
//set initial starting position
|
//snap initial starting position
|
||||||
entity.setNet(entity.interpolator().target.x, entity.interpolator().target.y);
|
entity.snapSync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(add){
|
if(add){
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import static mindustry.Vars.*;
|
|||||||
public class NetServer implements ApplicationListener{
|
public class NetServer implements ApplicationListener{
|
||||||
private final static int maxSnapshotSize = 430, timerBlockSync = 0;
|
private final static int maxSnapshotSize = 430, timerBlockSync = 0;
|
||||||
private final static float serverSyncTime = 12, blockSyncTime = 60 * 8;
|
private final static float serverSyncTime = 12, blockSyncTime = 60 * 8;
|
||||||
|
private final static FloatBuffer fbuffer = FloatBuffer.allocate(20);
|
||||||
private final static Vec2 vector = new Vec2();
|
private final static Vec2 vector = new Vec2();
|
||||||
private final static Rect viewport = new Rect();
|
private final static Rect viewport = new Rect();
|
||||||
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
|
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
|
||||||
@@ -598,34 +599,53 @@ public class NetServer implements ApplicationListener{
|
|||||||
float maxSpeed = player.dead() ? Float.MAX_VALUE : player.unit().type().speed;
|
float maxSpeed = player.dead() ? Float.MAX_VALUE : player.unit().type().speed;
|
||||||
float maxMove = elapsed / 1000f * 60f * maxSpeed * 1.1f;
|
float maxMove = elapsed / 1000f * 60f * maxSpeed * 1.1f;
|
||||||
|
|
||||||
vector.set(x - unit.interpolator().target.x, y - unit.interpolator().target.y);
|
if(connection.lastUnit != unit && !player.dead()){
|
||||||
|
connection.lastUnit = unit;
|
||||||
|
connection.lastPosition.set(unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector.set(x, y).sub(connection.lastPosition);
|
||||||
vector.limit(maxMove);
|
vector.limit(maxMove);
|
||||||
|
|
||||||
float prevx = unit.x(), prevy = unit.y();
|
float prevx = unit.x(), prevy = unit.y();
|
||||||
unit.set(unit.interpolator().target.x, unit.interpolator().target.y);
|
unit.set(connection.lastPosition);
|
||||||
if(!unit.isFlying()){
|
if(!unit.isFlying()){
|
||||||
unit.move(vector.x, vector.y);
|
unit.move(vector.x, vector.y);
|
||||||
}else{
|
}else{
|
||||||
unit.trns(vector.x, vector.y);
|
unit.trns(vector.x, vector.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set last position after movement
|
||||||
|
connection.lastPosition.set(unit);
|
||||||
float newx = unit.x(), newy = unit.y();
|
float newx = unit.x(), newy = unit.y();
|
||||||
|
|
||||||
if(!verifyPosition){
|
if(!verifyPosition){
|
||||||
unit.x(prevx);
|
unit.set(prevx, prevy);
|
||||||
unit.y(prevy);
|
|
||||||
newx = x;
|
newx = x;
|
||||||
newy = y;
|
newy = y;
|
||||||
}else if(Mathf.dst(x, y, newx, newy) > correctDist){
|
}else if(!Mathf.within(x, y, newx, newy, correctDist)){
|
||||||
Call.onPositionSet(player.con(), newx, newy); //teleport and correct position when necessary
|
Call.onPositionSet(player.con(), newx, newy); //teleport and correct position when necessary
|
||||||
}
|
}
|
||||||
|
|
||||||
//reset player to previous synced position so it gets interpolated
|
//reset player to previous synced position so it gets interpolated
|
||||||
unit.x(prevx);
|
unit.set(prevx, prevy);
|
||||||
unit.y(prevy);
|
|
||||||
|
|
||||||
//set interpolator target to *new* position so it moves toward it
|
//write sync data to the buffer
|
||||||
unit.interpolator().read(unit.x(), unit.y(), newx, newy, rotation, baseRotation);
|
fbuffer.limit(20);
|
||||||
unit.vel().set(xVelocity, yVelocity); //only for visual calculation purposes, doesn't actually update the player
|
fbuffer.position(0);
|
||||||
|
|
||||||
|
//now, put the new position, rotation and baserotation into the buffer so it can be read
|
||||||
|
if(unit instanceof Legsc) fbuffer.put(baseRotation); //base rotation is optional
|
||||||
|
fbuffer.put(rotation); //rotation is always there
|
||||||
|
fbuffer.put(newx);
|
||||||
|
fbuffer.put(newy);
|
||||||
|
fbuffer.flip();
|
||||||
|
|
||||||
|
//read sync data so it can be used for interpolation for the server
|
||||||
|
unit.readSyncManual(fbuffer);
|
||||||
|
|
||||||
|
//TODO fix
|
||||||
|
unit.vel().set(xVelocity, yVelocity); //only for visual calculation purposes, doesn't actually update the player (TODO or does it?)
|
||||||
}else{
|
}else{
|
||||||
player.x(x);
|
player.x(x);
|
||||||
player.y(y);
|
player.y(y);
|
||||||
@@ -795,7 +815,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
//write all entities now
|
//write all entities now
|
||||||
dataStream.writeInt(entity.id()); //write id
|
dataStream.writeInt(entity.id()); //write id
|
||||||
dataStream.writeByte(entity.classId()); //write type ID
|
dataStream.writeByte(entity.classId()); //write type ID
|
||||||
entity.write(Writes.get(dataStream)); //write entity
|
entity.writeSync(Writes.get(dataStream)); //write entity
|
||||||
|
|
||||||
sent++;
|
sent++;
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ import mindustry.gen.*;
|
|||||||
|
|
||||||
@Component
|
@Component
|
||||||
abstract class LegsComp implements Posc, Flyingc, Hitboxc, Unitc, Legsc, ElevationMovec{
|
abstract class LegsComp implements Posc, Flyingc, Hitboxc, Unitc, Legsc, ElevationMovec{
|
||||||
@Import float x, y;
|
@SyncField(false) float baseRotation;
|
||||||
|
|
||||||
float baseRotation;
|
|
||||||
transient float walkTime;
|
transient float walkTime;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package mindustry.entities.comp;
|
package mindustry.entities.comp;
|
||||||
|
|
||||||
|
import arc.math.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.async.PhysicsProcess.*;
|
import mindustry.async.PhysicsProcess.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
@@ -9,10 +10,17 @@ import mindustry.gen.*;
|
|||||||
* Has mass.*/
|
* Has mass.*/
|
||||||
@Component
|
@Component
|
||||||
abstract class PhysicsComp implements Velc, Hitboxc, Flyingc{
|
abstract class PhysicsComp implements Velc, Hitboxc, Flyingc{
|
||||||
transient PhysicRef physref;
|
@Import float hitSize;
|
||||||
transient float mass = 1f;
|
|
||||||
|
|
||||||
public void impulse(float x, float y){
|
transient PhysicRef physref;
|
||||||
|
|
||||||
|
//mass is simply the area of this object
|
||||||
|
float mass(){
|
||||||
|
return hitSize * hitSize * Mathf.pi;
|
||||||
|
}
|
||||||
|
|
||||||
|
void impulse(float x, float y){
|
||||||
|
float mass = mass();
|
||||||
vel().add(x / mass, y / mass);
|
vel().add(x / mass, y / mass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import static mindustry.Vars.world;
|
|||||||
|
|
||||||
@Component
|
@Component
|
||||||
abstract class PosComp implements Position{
|
abstract class PosComp implements Position{
|
||||||
float x, y;
|
@SyncField(true) float x, y;
|
||||||
|
|
||||||
void set(float x, float y){
|
void set(float x, float y){
|
||||||
this.x = x;
|
this.x = x;
|
||||||
|
|||||||
@@ -5,13 +5,5 @@ import mindustry.gen.*;
|
|||||||
|
|
||||||
@Component
|
@Component
|
||||||
abstract class RotComp implements Entityc{
|
abstract class RotComp implements Entityc{
|
||||||
float rotation;
|
@SyncField(false) float rotation;
|
||||||
|
|
||||||
void interpolate(){
|
|
||||||
Syncc sync = as(Syncc.class);
|
|
||||||
|
|
||||||
if(sync.interpolator().values.length > 0){
|
|
||||||
rotation = sync.interpolator().values[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,23 @@
|
|||||||
package mindustry.entities.comp;
|
package mindustry.entities.comp;
|
||||||
|
|
||||||
|
import arc.util.io.*;
|
||||||
import mindustry.*;
|
import mindustry.*;
|
||||||
import mindustry.annotations.Annotations.*;
|
import mindustry.annotations.Annotations.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
import mindustry.net.*;
|
|
||||||
|
import java.nio.*;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
abstract class SyncComp implements Posc{
|
abstract class SyncComp implements Entityc{
|
||||||
@Import float x, y;
|
transient long lastUpdated, updateSpacing;
|
||||||
|
|
||||||
transient Interpolator interpolator = new Interpolator();
|
//all these method bodies are internally generated
|
||||||
|
void snapSync(){}
|
||||||
void setNet(float x, float y){
|
void readSync(Reads read){}
|
||||||
set(x, y);
|
void writeSync(Writes write){}
|
||||||
|
void readSyncManual(FloatBuffer buffer){}
|
||||||
//TODO change interpolator API
|
void writeSyncManual(FloatBuffer buffer){}
|
||||||
interpolator.target.set(x, y);
|
void interpolate(){}
|
||||||
interpolator.last.set(x, y);
|
|
||||||
interpolator.pos.set(0, 0);
|
|
||||||
interpolator.updateSpacing = 16;
|
|
||||||
interpolator.lastUpdated = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void update(){
|
||||||
@@ -28,10 +25,4 @@ abstract class SyncComp implements Posc{
|
|||||||
interpolate();
|
interpolate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void interpolate(){
|
|
||||||
interpolator.update();
|
|
||||||
x = interpolator.pos.x;
|
|
||||||
y = interpolator.pos.y;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import static mindustry.Vars.*;
|
|||||||
|
|
||||||
/** Stores player unlocks. Clientside only. */
|
/** Stores player unlocks. Clientside only. */
|
||||||
public class GlobalData{
|
public class GlobalData{
|
||||||
private ObjectMap<ContentType, ObjectSet<String>> unlocked = new ObjectMap<>();
|
private ObjectSet<String> unlocked = new ObjectSet<>();
|
||||||
private ObjectIntMap<Item> items = new ObjectIntMap<>();
|
private ObjectIntMap<Item> items = new ObjectIntMap<>();
|
||||||
private boolean modified;
|
private boolean modified;
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ public class GlobalData{
|
|||||||
|
|
||||||
/** 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){
|
||||||
return content.alwaysUnlocked() || unlocked.getOr(content.getContentType(), ObjectSet::new).contains(content.name);
|
return content.alwaysUnlocked() || unlocked.contains(content.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -140,7 +140,7 @@ public class GlobalData{
|
|||||||
if(content.alwaysUnlocked()) return;
|
if(content.alwaysUnlocked()) return;
|
||||||
|
|
||||||
//fire unlock event so other classes can use it
|
//fire unlock event so other classes can use it
|
||||||
if(unlocked.getOr(content.getContentType(), ObjectSet::new).add(content.name)){
|
if(unlocked.add(content.name)){
|
||||||
modified = true;
|
modified = true;
|
||||||
content.onUnlock();
|
content.onUnlock();
|
||||||
Events.fire(new UnlockEvent(content));
|
Events.fire(new UnlockEvent(content));
|
||||||
@@ -162,7 +162,7 @@ public class GlobalData{
|
|||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void load(){
|
public void load(){
|
||||||
items.clear();
|
items.clear();
|
||||||
unlocked = Core.settings.getJson("unlocks", ObjectMap.class, ObjectMap::new);
|
unlocked = Core.settings.getJson("unlocked-content", ObjectSet.class, ObjectSet::new);
|
||||||
for(Item item : Vars.content.items()){
|
for(Item item : Vars.content.items()){
|
||||||
items.put(item, Core.settings.getInt("item-" + item.name, 0));
|
items.put(item, Core.settings.getInt("item-" + item.name, 0));
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ public class GlobalData{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void save(){
|
public void save(){
|
||||||
Core.settings.putJson("unlocks", unlocked);
|
Core.settings.putJson("unlocked-content", String.class, unlocked);
|
||||||
for(Item item : Vars.content.items()){
|
for(Item item : Vars.content.items()){
|
||||||
Core.settings.put("item-" + item.name, items.get(item, 0));
|
Core.settings.put("item-" + item.name, items.get(item, 0));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,6 +209,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
|
|
||||||
if(controlledType != null && player.dead()){
|
if(controlledType != null && player.dead()){
|
||||||
Unitc unit = Units.closest(player.team(), player.x(), player.y(), u -> !u.isPlayer() && u.type() == controlledType);
|
Unitc unit = Units.closest(player.team(), player.x(), player.y(), u -> !u.isPlayer() && u.type() == controlledType);
|
||||||
|
|
||||||
if(unit != null){
|
if(unit != null){
|
||||||
Call.onUnitControl(player, unit);
|
Call.onUnitControl(player, unit);
|
||||||
}
|
}
|
||||||
@@ -218,6 +219,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
public void checkUnit(){
|
public void checkUnit(){
|
||||||
if(controlledType != null){
|
if(controlledType != null){
|
||||||
Unitc unit = Units.closest(player.team(), player.x(), player.y(), u -> !u.isPlayer() && u.type() == controlledType);
|
Unitc unit = Units.closest(player.team(), player.x(), player.y(), u -> !u.isPlayer() && u.type() == controlledType);
|
||||||
|
if(unit == null && controlledType == UnitTypes.block){
|
||||||
|
unit = world.entWorld(player.x(), player.y()) instanceof ControlBlock ? ((ControlBlock)world.entWorld(player.x(), player.y())).unit() : null;
|
||||||
|
}
|
||||||
|
|
||||||
if(unit != null){
|
if(unit != null){
|
||||||
if(net.client()){
|
if(net.client()){
|
||||||
Call.onUnitControl(player, unit);
|
Call.onUnitControl(player, unit);
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
package mindustry.net;
|
|
||||||
|
|
||||||
import arc.math.*;
|
|
||||||
import arc.math.geom.*;
|
|
||||||
import arc.util.*;
|
|
||||||
|
|
||||||
public class Interpolator{
|
|
||||||
//used for movement
|
|
||||||
public Vec2 target = new Vec2();
|
|
||||||
public Vec2 last = new Vec2();
|
|
||||||
public float[] targets = {};
|
|
||||||
public float[] lasts = {};
|
|
||||||
public long lastUpdated, updateSpacing;
|
|
||||||
|
|
||||||
//current state
|
|
||||||
public Vec2 pos = new Vec2();
|
|
||||||
public float[] values = {};
|
|
||||||
|
|
||||||
public void read(float cx, float cy, float x, float y, float... target1ds){
|
|
||||||
if(lastUpdated != 0) updateSpacing = Time.timeSinceMillis(lastUpdated);
|
|
||||||
|
|
||||||
lastUpdated = Time.millis();
|
|
||||||
|
|
||||||
targets = target1ds;
|
|
||||||
if(lasts.length != values.length){
|
|
||||||
lasts = new float[values.length];
|
|
||||||
}
|
|
||||||
System.arraycopy(values, 0, lasts, 0, values.length);
|
|
||||||
last.set(cx, cy);
|
|
||||||
target.set(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void reset(){
|
|
||||||
values = new float[0];
|
|
||||||
targets = new float[0];
|
|
||||||
target.setZero();
|
|
||||||
last.setZero();
|
|
||||||
lastUpdated = 0;
|
|
||||||
updateSpacing = 16; //1 frame
|
|
||||||
pos.setZero();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void update(){
|
|
||||||
if(lastUpdated != 0 && updateSpacing != 0){
|
|
||||||
float timeSinceUpdate = Time.timeSinceMillis(lastUpdated);
|
|
||||||
float alpha = Math.min(timeSinceUpdate / updateSpacing, 2f);
|
|
||||||
|
|
||||||
pos.set(last).lerpPast(target, alpha);
|
|
||||||
|
|
||||||
if(values.length != targets.length){
|
|
||||||
values = new float[targets.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(lasts.length != targets.length){
|
|
||||||
lasts = new float[targets.length];
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < values.length; i++){
|
|
||||||
values[i] = Mathf.slerp(lasts[i], targets[i], alpha);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
pos.set(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package mindustry.net;
|
package mindustry.net;
|
||||||
|
|
||||||
|
import arc.math.geom.*;
|
||||||
import arc.struct.*;
|
import arc.struct.*;
|
||||||
import arc.util.ArcAnnotate.*;
|
import arc.util.ArcAnnotate.*;
|
||||||
import arc.util.*;
|
import arc.util.*;
|
||||||
@@ -18,6 +19,8 @@ public abstract class NetConnection{
|
|||||||
public String uuid = "AAAAAAAA", usid = uuid;
|
public String uuid = "AAAAAAAA", usid = uuid;
|
||||||
public boolean mobile, modclient;
|
public boolean mobile, modclient;
|
||||||
public @Nullable Playerc player;
|
public @Nullable Playerc player;
|
||||||
|
public @Nullable Unitc lastUnit;
|
||||||
|
public Vec2 lastPosition = new Vec2();
|
||||||
|
|
||||||
/** ID of last recieved client snapshot. */
|
/** ID of last recieved client snapshot. */
|
||||||
public int lastRecievedClientSnapshot = -1;
|
public int lastRecievedClientSnapshot = -1;
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class UnitType extends UnlockableContent{
|
|||||||
public @Nullable UnitType upgrade;
|
public @Nullable UnitType upgrade;
|
||||||
public int tier = 1;
|
public int tier = 1;
|
||||||
public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f;
|
public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f;
|
||||||
public float drag = 0.3f, mass = 1f, accel = 0.5f, landShake = 0f;
|
public float drag = 0.3f, accel = 0.5f, landShake = 0f;
|
||||||
public float health = 200f, range = -1, armor = 0f;
|
public float health = 200f, range = -1, armor = 0f;
|
||||||
public boolean targetAir = true, targetGround = true;
|
public boolean targetAir = true, targetGround = true;
|
||||||
public boolean faceTarget = true, isCounted = true, lowAltitude = false;
|
public boolean faceTarget = true, isCounted = true, lowAltitude = false;
|
||||||
|
|||||||
@@ -84,8 +84,6 @@ public class OverflowGate extends Block{
|
|||||||
lastItem = item;
|
lastItem = item;
|
||||||
time = 0f;
|
time = 0f;
|
||||||
lastInput = source.tile();
|
lastInput = source.tile();
|
||||||
|
|
||||||
updateTile();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable Tilec getTileTarget(Item item, Tile src, boolean flip){
|
public @Nullable Tilec getTileTarget(Item item, Tile src, boolean flip){
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ public class UnitBlock extends PayloadAcceptor{
|
|||||||
Unitc unit = payload.unit;
|
Unitc unit = payload.unit;
|
||||||
unit.set(x, y);
|
unit.set(x, y);
|
||||||
unit.rotation(rotdeg());
|
unit.rotation(rotdeg());
|
||||||
unit.vel().trns(rotdeg(), payloadSpeed * 2f).add(Mathf.range(0.1f), Mathf.range(0.1f));
|
unit.vel().trns(rotdeg(), payloadSpeed * 2f).add(Mathf.range(0.3f), Mathf.range(0.3f));
|
||||||
unit.trns(Tmp.v1.trns(rotdeg(), size * tilesize/2f));
|
unit.trns(Tmp.v1.trns(rotdeg(), size * tilesize/2f));
|
||||||
unit.trns(unit.vel());
|
unit.trns(unit.vel());
|
||||||
unit.add();
|
unit.add();
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ public class UnitFactory extends UnitBlock{
|
|||||||
hasPower = true;
|
hasPower = true;
|
||||||
hasItems = true;
|
hasItems = true;
|
||||||
solid = true;
|
solid = true;
|
||||||
flags = EnumSet.of(BlockFlag.producer, BlockFlag.unitModifier);
|
//flags = EnumSet.of(BlockFlag.producer, BlockFlag.unitModifier);
|
||||||
unitCapModifier = 4;
|
//unitCapModifier = 2;
|
||||||
configurable = true;
|
configurable = true;
|
||||||
outputsPayload = true;
|
outputsPayload = true;
|
||||||
rotate = true;
|
rotate = true;
|
||||||
|
|||||||
Reference in New Issue
Block a user