started re-implementing route reservation
This commit is contained in:
@@ -146,10 +146,17 @@ public abstract class Block extends StretchableTile{
|
||||
return t("Trigger contact to learn new contact");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canNeEnteredBy(Train newTrain) {
|
||||
if (!super.canNeEnteredBy(newTrain)) return false;
|
||||
if (parkedTrains.isEmpty()) return true;
|
||||
return isNull(newTrain) ? false : newTrain.isShunting(); // block contains train(s), thus it is only free for shunting train
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HashSet<String> classes() {
|
||||
HashSet<String> classes = super.classes();
|
||||
if (!parkedTrains.isEmpty()) classes.add(OCCUPIED);
|
||||
if (!parkedTrains.isEmpty()) classes.add(Status.OCCUPIED.toString());
|
||||
return classes;
|
||||
}
|
||||
|
||||
@@ -229,14 +236,6 @@ public abstract class Block extends StretchableTile{
|
||||
return 1+internalContacts.indexOf(contact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFreeFor(Context context) {
|
||||
if (!super.isFreeFor(context)) return false;
|
||||
if (parkedTrains.isEmpty()) return true;
|
||||
Train t = isSet(context) ? context.train() : null;
|
||||
return isSet(t) ? t.isShunting() : false; // block contains train(s), thus it is olny free for shunting train
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject json() {
|
||||
JSONObject json = super.json();
|
||||
@@ -358,7 +357,6 @@ public abstract class Block extends StretchableTile{
|
||||
super.removeChild(child);
|
||||
internalContacts.remove(child);
|
||||
if (parkedTrains.remove(child)) plan.place(this);
|
||||
if (train == child) setTrain(null);
|
||||
}
|
||||
|
||||
public void removeContact(BlockContact blockContact) {
|
||||
|
||||
@@ -27,11 +27,6 @@ public class BlockContact extends Contact {
|
||||
return new Id(block.name+":"+block.indexOf(this));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Route route() {
|
||||
return ((Block)parent()).route();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag tag(Map<String, Object> replacements) throws IOException {
|
||||
return ((Block)parent()).tag(replacements);
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.json.JSONObject;
|
||||
import de.srsoftware.tools.Tag;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.Connector;
|
||||
import de.srsoftware.web4rail.Route;
|
||||
import de.srsoftware.web4rail.moving.Train;
|
||||
import de.srsoftware.web4rail.tags.Fieldset;
|
||||
import de.srsoftware.web4rail.tags.Window;
|
||||
@@ -42,6 +41,12 @@ public abstract class Bridge extends Tile {
|
||||
|
||||
protected abstract Connector connector();
|
||||
|
||||
@Override
|
||||
public void free() {
|
||||
if (isSet(counterpart) && counterpart.train != null) counterpart.free();
|
||||
super.free();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject json() {
|
||||
JSONObject json = super.json();
|
||||
@@ -63,16 +68,10 @@ public abstract class Bridge extends Tile {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile setRoute(Route route) {
|
||||
super.setRoute(route);
|
||||
if (isSet(counterpart) && counterpart.route != route) counterpart.setRoute(route);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Tile setTrain(Train train) {
|
||||
super.setTrain(train);
|
||||
if (isSet(counterpart) && counterpart.train != train) counterpart.setTrain(train);
|
||||
return this;
|
||||
public boolean setState(Status newState, Train newTrain) {
|
||||
if (train == newTrain && is(newState)) return true;
|
||||
if (!super.setState(newState,newTrain)) return false;
|
||||
return isNull(counterpart) ? true : counterpart.setState(newState,newTrain);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,11 +108,4 @@ public abstract class Bridge extends Tile {
|
||||
if (isNull(counterpart)) tag.clazz(tag.get("class")+" disconnected");
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile unset(Route oldRoute) {
|
||||
super.unset(oldRoute);
|
||||
if (isSet(counterpart) && isSet(counterpart.route)) counterpart.unset(oldRoute);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import org.slf4j.LoggerFactory;
|
||||
import de.srsoftware.tools.Tag;
|
||||
import de.srsoftware.web4rail.Application;
|
||||
import de.srsoftware.web4rail.BaseClass;
|
||||
import de.srsoftware.web4rail.Route;
|
||||
import de.srsoftware.web4rail.actions.Action;
|
||||
import de.srsoftware.web4rail.actions.ActionList;
|
||||
import de.srsoftware.web4rail.tags.Fieldset;
|
||||
@@ -85,12 +84,12 @@ public class Contact extends Tile{
|
||||
LOG.debug("{} activated.",this);
|
||||
state = true;
|
||||
if (isSet(timer)) timer.abort();
|
||||
Route route = route();
|
||||
Context context = isSet(route) ? route.context().contact(this) : new Context(this);
|
||||
|
||||
if (isSet(route)) route.traceTrainFrom(this);
|
||||
Context context = new Context(this);
|
||||
if (isSet(train)) {
|
||||
train.contact(this);
|
||||
context.train(train);
|
||||
}
|
||||
actions.fire(context,"Contact("+addr+")");
|
||||
if (isSet(route)) route.contact(this);
|
||||
|
||||
for (Listener listener : listeners) listener.fired("Contact("+addr+")");
|
||||
|
||||
|
||||
@@ -40,12 +40,27 @@ import de.srsoftware.web4rail.threads.PathFinder;
|
||||
*
|
||||
*/
|
||||
public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
public enum Status{
|
||||
FREE("free"),
|
||||
ALLOCATED("allocated"),
|
||||
LOCKED("locked"),
|
||||
OCCUPIED("occupied");
|
||||
|
||||
private String tx;
|
||||
|
||||
Status(String s) {
|
||||
tx = s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return tx;
|
||||
}
|
||||
}
|
||||
protected static Logger LOG = LoggerFactory.getLogger(Tile.class);
|
||||
private static int DEFAUT_LENGTH = 100; // 10cm
|
||||
|
||||
private static final String LENGTH = "length";
|
||||
private static final String LOCKED = "locked";
|
||||
protected static final String OCCUPIED = "occupied";
|
||||
private static final String ONEW_WAY = "one_way";
|
||||
private static final String POS = "pos";
|
||||
private static final String TYPE = "type";
|
||||
@@ -56,8 +71,8 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
private boolean isTrack = true;
|
||||
private int length = DEFAUT_LENGTH;
|
||||
protected Direction oneWay = null;
|
||||
protected Route route = null;
|
||||
private TreeSet<Route> routes = new TreeSet<>((r1,r2)->r1.toString().compareTo(r2.toString()));
|
||||
private Status status = Status.FREE;
|
||||
protected Train train = null;
|
||||
public Integer x = null;
|
||||
public Integer y = null;
|
||||
@@ -65,13 +80,38 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
public void add(Route route) {
|
||||
this.routes.add(route);
|
||||
}
|
||||
|
||||
public boolean canNeEnteredBy(Train newTrain) {
|
||||
PathFinder.LOG.debug("{}.canNeEnteredBy({})",this,newTrain);
|
||||
if (disabled) {
|
||||
PathFinder.LOG.debug("{} is disabled!",this);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNull(train)) {
|
||||
PathFinder.LOG.debug("→ free");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (newTrain == train) { // during train.reserveNext, we may encounter, parts, that are already reserved by the respective train, but having another route. do not compare routes in that case!
|
||||
PathFinder.LOG.debug("already reserved by {} → true",train);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isSet(newTrain) && newTrain.isShunting()) {
|
||||
PathFinder.LOG.debug("occupied by {}. Allowed for shunting {}",train,newTrain);
|
||||
return true;
|
||||
}
|
||||
|
||||
PathFinder.LOG.debug("occupied by {} → false",train);
|
||||
return false;
|
||||
}
|
||||
|
||||
protected HashSet<String> classes(){
|
||||
HashSet<String> classes = new HashSet<String>();
|
||||
classes.add("tile");
|
||||
classes.add(getClass().getSimpleName());
|
||||
if (isSet(route)) classes.add(LOCKED);
|
||||
if (isSet(train)) classes.add(OCCUPIED);
|
||||
classes.add(getClass().getSimpleName());
|
||||
if (!is(Status.FREE)) classes.add(status.toString());
|
||||
if (disabled) classes.add(DISABLED);
|
||||
return classes;
|
||||
}
|
||||
@@ -96,6 +136,11 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
return new HashMap<>();
|
||||
}
|
||||
|
||||
public void free() {
|
||||
train = null;
|
||||
status = Status.FREE;
|
||||
}
|
||||
|
||||
public int height() {
|
||||
return 1;
|
||||
}
|
||||
@@ -115,58 +160,18 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
if (tile instanceof TileWithShadow) ((TileWithShadow)tile).placeShadows();
|
||||
plan.place(tile);
|
||||
}
|
||||
|
||||
public boolean isFreeFor(Context context) {
|
||||
PathFinder.LOG.debug("{}.isFreeFor({})",this,context);
|
||||
if (disabled) {
|
||||
PathFinder.LOG.debug("{} is disabled!",this);
|
||||
return false;
|
||||
|
||||
public boolean is(Status...states) {
|
||||
for (Status s: states) {
|
||||
if (status == s) return true;
|
||||
}
|
||||
if (isNull(context)) {
|
||||
if (isSet(train)) {
|
||||
PathFinder.LOG.debug("{} is occupied by {}",this,train);
|
||||
return false;
|
||||
}
|
||||
if (isSet(route)) {
|
||||
PathFinder.LOG.debug("{} is occupied by {}",this,route);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (isSet(train)) {
|
||||
Train contextTrain = context.train();
|
||||
boolean free = train == contextTrain; // during train.reserveNext, we may encounter, parts, that are already reserved by the respective train, but having another route. do not compare routes in that case!
|
||||
if (free) {
|
||||
PathFinder.LOG.debug("already reserved by {} → true",train);
|
||||
} else {
|
||||
if (isSet(contextTrain) && contextTrain.isShunting()) {
|
||||
PathFinder.LOG.debug("occupied by {}. Allowed for shunting {}",train,contextTrain);
|
||||
free = true;
|
||||
} else PathFinder.LOG.debug("occupied by {} → false",train);
|
||||
}
|
||||
return free;
|
||||
}
|
||||
|
||||
// if we get here, the tile is not occupied by a train, but reserved by a route, yet. thus, the tile is not available for another route
|
||||
if (isSet(route) && route != context.route()) {
|
||||
PathFinder.LOG.debug("reserved by other route: {}",route);
|
||||
if (isSet(route.train())) {
|
||||
if (route.train() == context.train()) {
|
||||
PathFinder.LOG.debug("that route is used by {}, which is also requesting this tile → true",route.train());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
PathFinder.LOG.debug("{}.route.train = {} → false",this,route.train());
|
||||
return false;
|
||||
}
|
||||
PathFinder.LOG.debug("free");
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public JSONObject json() {
|
||||
JSONObject json = super.json();
|
||||
json.put(TYPE, getClass().getSimpleName());
|
||||
if (isSet(x) && isSet(y)) json.put(POS, new JSONObject(Map.of(X,x,Y,y)));
|
||||
if (isSet(route)) json.put(ROUTE, route.id());
|
||||
if (isSet(oneWay)) json.put(ONEW_WAY, oneWay);
|
||||
if (disabled) json.put(DISABLED, true);
|
||||
if (isSet(train)) json.put(REALM_TRAIN, train.id());
|
||||
@@ -242,7 +247,7 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
protected void noTrack() {
|
||||
isTrack = false;
|
||||
}
|
||||
|
||||
|
||||
public Tile position(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
@@ -256,16 +261,9 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
@Override
|
||||
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
|
||||
Fieldset fieldset = null;
|
||||
|
||||
if (isSet(route)) {
|
||||
fieldset = new Fieldset(t("Route"));
|
||||
route.link("p",t("Locked by {}",route)).addTo(fieldset);
|
||||
}
|
||||
|
||||
if (isSet(train)) {
|
||||
if (isSet(fieldset)) {
|
||||
fieldset.children().firstElement().content(" / "+t("Train"));
|
||||
} else fieldset = new Fieldset(t("Train"));
|
||||
fieldset = new Fieldset(t("Train"));
|
||||
train.link("span", t("Train")+":"+NBSP+train+NBSP).addTo(fieldset);
|
||||
if (isSet(train.route())) {
|
||||
train.button(t("stop"), Map.of(ACTION,ACTION_STOP)).addTo(fieldset);
|
||||
@@ -352,10 +350,6 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
public Route route() {
|
||||
return route;
|
||||
}
|
||||
|
||||
public TreeSet<Route> routes() {
|
||||
return routes;
|
||||
@@ -370,24 +364,16 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
file.close();
|
||||
}
|
||||
|
||||
public Tile setTrain(Train newTrain) {
|
||||
LOG.debug("{}.setTrain({})",this,newTrain);
|
||||
if (newTrain == train) return this; // nothing to update
|
||||
this.train = newTrain;
|
||||
return plan.place(this);
|
||||
}
|
||||
|
||||
public Tile setRoute(Route lockingRoute) {
|
||||
LOG.debug("{}.setRoute({})",this,lockingRoute);
|
||||
if (isNull(lockingRoute)) throw new NullPointerException();
|
||||
if (isSet(route)) {
|
||||
if (route == lockingRoute) return this; // nothing changed
|
||||
throw new IllegalStateException(this.toString()); // tile already locked by other route
|
||||
}
|
||||
route = lockingRoute;
|
||||
return plan.place(this);
|
||||
public boolean setState(Status newState,Train newTrain) {
|
||||
if (isNull(newTrain)) return false;
|
||||
if (isSet(train) && newTrain != train) return false; // already locked by other train
|
||||
if (is(Status.OCCUPIED,newState)) return true; // do not downgrade occupied tiles, accept current state
|
||||
train = newTrain;
|
||||
status = newState;
|
||||
plan.place(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public Tag tag(Map<String,Object> replacements) throws IOException {
|
||||
int width = 100*width();
|
||||
int height = 100*height();
|
||||
@@ -477,7 +463,6 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
if (child instanceof Route) routes.remove(child);
|
||||
|
||||
if (child == train) train = null;
|
||||
if (child == route) route = null;
|
||||
super.removeChild(child);
|
||||
plan.place(this);
|
||||
}
|
||||
@@ -487,22 +472,6 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
|
||||
plan.place(this);
|
||||
}
|
||||
|
||||
public void unlock() {
|
||||
route = null;
|
||||
train = null;
|
||||
plan.place(this);
|
||||
}
|
||||
|
||||
public Tile unset(Route oldRoute) {
|
||||
LOG.debug("{}.unset({})",this,oldRoute);
|
||||
if (route == null) return this;
|
||||
if (route == oldRoute) {
|
||||
route = null;
|
||||
return plan.place(this);
|
||||
}
|
||||
throw new IllegalArgumentException(t("{} not occupied by {}!",this,oldRoute));
|
||||
}
|
||||
|
||||
public Tile update(HashMap<String, String> params) {
|
||||
LOG.debug("{}.update({})",getClass().getSimpleName(),params);
|
||||
String oneWayDir = params.get("oneway");
|
||||
|
||||
@@ -159,7 +159,7 @@ public abstract class Turnout extends Tile implements Device{
|
||||
}
|
||||
|
||||
public Reply state(State newState) {
|
||||
if (train != null && newState != state) return new Reply(415, t("{} locked by {}!",this,train));
|
||||
if (is(Status.LOCKED,Status.OCCUPIED) && newState != state) return new Reply(415, t("{} locked by {}!",this,train));
|
||||
if (address == 0) {
|
||||
state = newState;
|
||||
plan.place(this);
|
||||
|
||||
@@ -16,8 +16,8 @@ public abstract class TurnoutL extends Turnout {
|
||||
public Object click(boolean shift) throws IOException {
|
||||
Object o = super.click(shift);
|
||||
if (!shift) {
|
||||
if (route != null) {
|
||||
plan.stream(t("{} is locked by {}!",this,route));
|
||||
if (isSet(train)) {
|
||||
plan.stream(t("{} is locked by {}!",this,train));
|
||||
} else state(state == State.STRAIGHT ? State.LEFT : State.STRAIGHT);
|
||||
}
|
||||
return o;
|
||||
|
||||
@@ -16,8 +16,8 @@ public abstract class TurnoutR extends Turnout {
|
||||
public Object click(boolean shift) throws IOException {
|
||||
Object o = super.click(shift);
|
||||
if (!shift) {
|
||||
if (route != null) {
|
||||
plan.stream(t("{} is locked by {}!",this,route));
|
||||
if (isSet(train)) {
|
||||
plan.stream(t("{} is locked by {}!",this,train));
|
||||
} else state(state == State.STRAIGHT ? State.RIGHT : State.STRAIGHT);
|
||||
}
|
||||
return o;
|
||||
|
||||
Reference in New Issue
Block a user