Add logic filter (#7251)
* logic filter * bundles * available in map editor * @this = null * generating only * ensure not using net --------- Co-authored-by: Anuken <arnukren@gmail.com>
This commit is contained in:
@@ -590,6 +590,7 @@ filter.clear = Clear
|
|||||||
filter.option.ignore = Ignore
|
filter.option.ignore = Ignore
|
||||||
filter.scatter = Scatter
|
filter.scatter = Scatter
|
||||||
filter.terrain = Terrain
|
filter.terrain = Terrain
|
||||||
|
filter.logic = Logic
|
||||||
|
|
||||||
filter.option.scale = Scale
|
filter.option.scale = Scale
|
||||||
filter.option.chance = Chance
|
filter.option.chance = Chance
|
||||||
@@ -613,6 +614,8 @@ filter.option.floor2 = Secondary Floor
|
|||||||
filter.option.threshold2 = Secondary Threshold
|
filter.option.threshold2 = Secondary Threshold
|
||||||
filter.option.radius = Radius
|
filter.option.radius = Radius
|
||||||
filter.option.percentile = Percentile
|
filter.option.percentile = Percentile
|
||||||
|
filter.option.code = Code
|
||||||
|
filter.option.loop = Loop
|
||||||
|
|
||||||
locales.info = Here, you can add locale bundles for specific languages to your map. In locale bundles, each property has a name and a value. These properties can be used by world processors and objectives using their names. They support text formatting (replacing placeholders with actual values).\n\n[cyan]Example property:\n[]name: [accent]timer[]\nvalue: [accent]Example timer, time left: {0}[]\n\n[cyan]Usage:\n[]Set it as objective's text: [accent]@timer\n\n[]Print it in a world processor:\n[accent]localeprint "timer"\nformat time\n[gray](where time is a separately calculated variable)
|
locales.info = Here, you can add locale bundles for specific languages to your map. In locale bundles, each property has a name and a value. These properties can be used by world processors and objectives using their names. They support text formatting (replacing placeholders with actual values).\n\n[cyan]Example property:\n[]name: [accent]timer[]\nvalue: [accent]Example timer, time left: {0}[]\n\n[cyan]Usage:\n[]Set it as objective's text: [accent]@timer\n\n[]Print it in a world processor:\n[accent]localeprint "timer"\nformat time\n[gray](where time is a separately calculated variable)
|
||||||
locales.deletelocale = Are you sure you want to delete this locale bundle?
|
locales.deletelocale = Are you sure you want to delete this locale bundle?
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ public class LExecutor{
|
|||||||
public @Nullable LogicBuild build;
|
public @Nullable LogicBuild build;
|
||||||
public IntSet linkIds = new IntSet();
|
public IntSet linkIds = new IntSet();
|
||||||
public Team team = Team.derelict;
|
public Team team = Team.derelict;
|
||||||
public boolean privileged = false;
|
public boolean privileged = false, isFilter = false;
|
||||||
|
|
||||||
//yes, this is a minor memory leak, but it's probably not significant enough to matter
|
//yes, this is a minor memory leak, but it's probably not significant enough to matter
|
||||||
protected static IntFloatMap unitTimeouts = new IntFloatMap();
|
protected static IntFloatMap unitTimeouts = new IntFloatMap();
|
||||||
@@ -1479,7 +1479,7 @@ public class LExecutor{
|
|||||||
if(t == null) t = Team.derelict;
|
if(t == null) t = Team.derelict;
|
||||||
|
|
||||||
if(tile.block() != b || tile.team() != t){
|
if(tile.block() != b || tile.team() != t){
|
||||||
tile.setNet(b, t, Mathf.clamp(exec.numi(rotation), 0, 3));
|
tile.setBlock(b, t, Mathf.clamp(exec.numi(rotation), 0, 3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class Maps{
|
|||||||
NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new,
|
NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new,
|
||||||
RiverNoiseFilter::new, OreFilter::new, OreMedianFilter::new, MedianFilter::new,
|
RiverNoiseFilter::new, OreFilter::new, OreMedianFilter::new, MedianFilter::new,
|
||||||
BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new,
|
BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new,
|
||||||
EnemySpawnFilter::new, SpawnPathFilter::new
|
EnemySpawnFilter::new, SpawnPathFilter::new, LogicFilter::new
|
||||||
};
|
};
|
||||||
|
|
||||||
/** List of all built-in maps. Filenames only. */
|
/** List of all built-in maps. Filenames only. */
|
||||||
|
|||||||
82
core/src/mindustry/maps/filters/LogicFilter.java
Normal file
82
core/src/mindustry/maps/filters/LogicFilter.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package mindustry.maps.filters;
|
||||||
|
|
||||||
|
import arc.scene.ui.layout.*;
|
||||||
|
import mindustry.gen.*;
|
||||||
|
import mindustry.logic.*;
|
||||||
|
import mindustry.maps.filters.FilterOption.*;
|
||||||
|
import mindustry.world.*;
|
||||||
|
|
||||||
|
import static mindustry.Vars.*;
|
||||||
|
|
||||||
|
public class LogicFilter extends GenerateFilter{
|
||||||
|
/** max available execution for logic filter */
|
||||||
|
public static int maxInstructionsExecution = 500 * 500 * 25;
|
||||||
|
public String code;
|
||||||
|
public boolean loop;
|
||||||
|
LExecutor executor;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FilterOption[] options(){
|
||||||
|
return new FilterOption[]{
|
||||||
|
new FilterOption(){
|
||||||
|
final String name;
|
||||||
|
{
|
||||||
|
name = "code";
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void build(Table table){
|
||||||
|
table.button(b -> b.image(Icon.pencil).size(iconSmall), () -> {
|
||||||
|
ui.logic.show(code, null, true, code -> LogicFilter.this.code = code);
|
||||||
|
}).pad(4).margin(12f);
|
||||||
|
|
||||||
|
table.add("@filter.option." + name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new ToggleOption("loop", () -> loop, f -> loop = f)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(Tiles tiles, GenerateInput in){
|
||||||
|
executor = new LExecutor();
|
||||||
|
executor.privileged = true;
|
||||||
|
executor.isFilter = true;
|
||||||
|
configure(code);
|
||||||
|
|
||||||
|
//limited run
|
||||||
|
for(int i = 1; i < maxInstructionsExecution; i++){
|
||||||
|
if(!loop && (executor.counter.numval >= executor.instructions.length || executor.counter.numval < 0)) break;
|
||||||
|
executor.runOnce();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char icon(){
|
||||||
|
return Iconc.blockMicroProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPost(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void configure(String code){
|
||||||
|
try{
|
||||||
|
//create assembler to store extra variables
|
||||||
|
LAssembler asm = LAssembler.assemble(code, true);
|
||||||
|
|
||||||
|
asm.putConst("@mapw", world.width());
|
||||||
|
asm.putConst("@maph", world.height());
|
||||||
|
asm.putConst("@links", executor.links.length);
|
||||||
|
asm.putConst("@ipt", 1);
|
||||||
|
|
||||||
|
asm.putConst("@thisx", 0);
|
||||||
|
asm.putConst("@thisy", 0);
|
||||||
|
|
||||||
|
executor.load(asm);
|
||||||
|
}catch(Exception e){
|
||||||
|
//handle malformed code and replace it with nothing
|
||||||
|
executor.load(LAssembler.assemble(code = "", true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user