Updated Wildfire: Added support for synchronized loading of event logs.
A fire log can now be loaded at startup time with, e.g., --prop:environment/wildfire/events-file=$HOME/.fgfs/Wildfire/small_fire.xml (Note: Wildfire is only authorized to load logs from ~/.fgfs/Wildfire .) Additionally, a time at which the fire starts to evolve (past the event log) can be specified with, e.g., --prop:environment/wildfire/time-hack-gmt='2012:08:23:15:15' Instances of FlightGear that are started with the same event log and time-hack should arrive at similar wildfire states (prior to new events).
This commit is contained in:
parent
f5bfd65f72
commit
acd0091d9d
1 changed files with 79 additions and 16 deletions
|
@ -95,7 +95,7 @@ var resolve_foam_drop = func (pos, radius, volume, source=1) {
|
||||||
# x < last event - fast forward all the way to current time (use 0).
|
# x < last event - fast forward all the way to current time (use 0).
|
||||||
# NOTE: Can be VERY time consuming.
|
# NOTE: Can be VERY time consuming.
|
||||||
# -1 - skip to current time.
|
# -1 - skip to current time.
|
||||||
var load_event_log = func (filename, skip_ahead_until=-1) {
|
var load_event_log = func (filename, skip_ahead_until) {
|
||||||
CAFire.load_event_log(filename, skip_ahead_until);
|
CAFire.load_event_log(filename, skip_ahead_until);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,6 +129,9 @@ var restore_on_startup_pp = "environment/wildfire/restore-on-startup";
|
||||||
var crash_fire_pp = "environment/wildfire/fire-on-crash";
|
var crash_fire_pp = "environment/wildfire/fire-on-crash";
|
||||||
var impact_fire_pp = "environment/wildfire/fire-on-impact";
|
var impact_fire_pp = "environment/wildfire/fire-on-impact";
|
||||||
var report_score_pp = "environment/wildfire/report-score";
|
var report_score_pp = "environment/wildfire/report-score";
|
||||||
|
var event_file_pp = "environment/wildfire/events-file";
|
||||||
|
var time_hack_pp = "environment/wildfire/time-hack-gmt";
|
||||||
|
# Format: "yyyy:mm:dd:hh:mm:ss"
|
||||||
# Internal properties to control the models
|
# Internal properties to control the models
|
||||||
var models_enabled_pp = "environment/wildfire/models/enabled";
|
var models_enabled_pp = "environment/wildfire/models/enabled";
|
||||||
var fire_LOD_pp = "environment/wildfire/models/fire-lod";
|
var fire_LOD_pp = "environment/wildfire/models/fire-lod";
|
||||||
|
@ -788,7 +791,7 @@ CAFire.save_event_log = func (filename) {
|
||||||
# to current time.
|
# to current time.
|
||||||
# x < last event - fast forward all the way to current time (use 0).
|
# x < last event - fast forward all the way to current time (use 0).
|
||||||
# -1 - skip to current time.
|
# -1 - skip to current time.
|
||||||
CAFire.load_event_log = func (filename, skip_ahead_until=-1) {
|
CAFire.load_event_log = func (filename, skip_ahead_until) {
|
||||||
me.load_count += 1;
|
me.load_count += 1;
|
||||||
var logbase = "/tmp/wildfire-load-log[" ~ me.load_count ~ "]";
|
var logbase = "/tmp/wildfire-load-log[" ~ me.load_count ~ "]";
|
||||||
if (!fgcommand("loadxml",
|
if (!fgcommand("loadxml",
|
||||||
|
@ -814,7 +817,7 @@ CAFire.load_event_log = func (filename, skip_ahead_until=-1) {
|
||||||
event.getNode("type").getValue()];
|
event.getNode("type").getValue()];
|
||||||
|
|
||||||
# Fast forward state.
|
# Fast forward state.
|
||||||
while (me.generation * me.GENERATION_DURATION <= e[0]) {
|
while (me.generation * me.GENERATION_DURATION < e[0]) {
|
||||||
# print("between event ff " ~ me.generation);
|
# print("between event ff " ~ me.generation);
|
||||||
me.update();
|
me.update();
|
||||||
}
|
}
|
||||||
|
@ -958,6 +961,8 @@ _setlistener("/sim/signals/nasal-dir-initialized", func {
|
||||||
props.globals.initNode(restore_on_startup_pp, 0, "BOOL");
|
props.globals.initNode(restore_on_startup_pp, 0, "BOOL");
|
||||||
props.globals.initNode(models_enabled_pp, 1, "BOOL");
|
props.globals.initNode(models_enabled_pp, 1, "BOOL");
|
||||||
props.globals.initNode(report_score_pp, 1, "BOOL");
|
props.globals.initNode(report_score_pp, 1, "BOOL");
|
||||||
|
props.globals.initNode(event_file_pp, "", "STRING");
|
||||||
|
props.globals.initNode(time_hack_pp, "", "STRING");
|
||||||
|
|
||||||
props.globals.initNode(fire_LOD_pp, 10, "INT");
|
props.globals.initNode(fire_LOD_pp, 10, "INT");
|
||||||
props.globals.initNode(smoke_LOD_pp, 10, "INT");
|
props.globals.initNode(smoke_LOD_pp, 10, "INT");
|
||||||
|
@ -977,10 +982,35 @@ _setlistener("/sim/signals/nasal-dir-initialized", func {
|
||||||
CAFire.save_event_log(SAVEDIR ~ "fire_log.xml");
|
CAFire.save_event_log(SAVEDIR ~ "fire_log.xml");
|
||||||
});
|
});
|
||||||
|
|
||||||
if (getprop(restore_on_startup_pp)) {
|
# Determine the skip-ahead-to time, if any.
|
||||||
|
var time_hack = time_string_to_epoch(getprop(time_hack_pp));
|
||||||
|
if (time_hack > SimTime.current_time()) {
|
||||||
|
printlog("alert",
|
||||||
|
"wildfire.nas: Ignored time hack " ~
|
||||||
|
(SimTime.current_time() - time_hack) ~
|
||||||
|
" seconds into the future.");
|
||||||
|
# Skip ahead to current time instead.
|
||||||
|
time_hack = -1;
|
||||||
|
} elsif (time_hack > 0) {
|
||||||
|
printlog("alert",
|
||||||
|
"wildfire.nas: Time hack " ~
|
||||||
|
(SimTime.current_time() - time_hack) ~
|
||||||
|
" seconds ago.");
|
||||||
|
} else {
|
||||||
|
# Skip ahead to current time instead.
|
||||||
|
time_hack = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getprop(event_file_pp) != "") {
|
||||||
settimer(func {
|
settimer(func {
|
||||||
# Delay loading the log until the terrain is there. Note: hack.
|
# Delay loading the log until the terrain is there. Note: hack.
|
||||||
CAFire.load_event_log(SAVEDIR ~ "fire_log.xml", 1);
|
CAFire.load_event_log(getprop(event_file_pp), time_hack);
|
||||||
|
}, 3);
|
||||||
|
} elsif (getprop(restore_on_startup_pp)) {
|
||||||
|
settimer(func {
|
||||||
|
# Delay loading the log until the terrain is there. Note: hack.
|
||||||
|
# Restore skips ahead to current time.
|
||||||
|
CAFire.load_event_log(SAVEDIR ~ "fire_log.xml", -1);
|
||||||
}, 3);
|
}, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -990,17 +1020,16 @@ _setlistener("/sim/signals/nasal-dir-initialized", func {
|
||||||
wildfire.ignite(geo.aircraft_position());
|
wildfire.ignite(geo.aircraft_position());
|
||||||
});
|
});
|
||||||
|
|
||||||
# Detect impact
|
# Detect impact.
|
||||||
var impact_node = props.globals.getNode("sim/ai/aircraft/impact/bomb", 1);
|
var impact_node = props.globals.getNode("sim/ai/aircraft/impact/bomb", 1);
|
||||||
setlistener("sim/ai/aircraft/impact/bomb", func(n) {
|
setlistener("sim/ai/aircraft/impact/bomb", func(n) {
|
||||||
|
|
||||||
if (getprop(impact_fire_pp) and n.getBoolValue()){
|
if (getprop(impact_fire_pp) and n.getBoolValue()){
|
||||||
var node = props.globals.getNode(n.getValue(), 1);
|
var node = props.globals.getNode(n.getValue(), 1);
|
||||||
var impactpos = geo.Coord.new();
|
var impactpos = geo.Coord.new();
|
||||||
impactpos.set_latlon(
|
impactpos.set_latlon
|
||||||
node.getNode("impact/latitude-deg").getValue(),
|
(node.getNode("impact/latitude-deg").getValue(),
|
||||||
node.getNode("impact/longitude-deg").getValue()
|
node.getNode("impact/longitude-deg").getValue());
|
||||||
);
|
|
||||||
wildfire.ignite(impactpos);
|
wildfire.ignite(impactpos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1010,6 +1039,40 @@ _setlistener("/sim/signals/nasal-dir-initialized", func {
|
||||||
});
|
});
|
||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# Utility functions
|
||||||
|
|
||||||
|
# Convert a time string in the format yyyy[:mm[:dd[:hh[:mm[:ss]]]]]
|
||||||
|
# to seconds since 1970:01:01:00:00:00.
|
||||||
|
#
|
||||||
|
# Note: This is an over simplified approximation.
|
||||||
|
var time_string_to_epoch = func (time) {
|
||||||
|
var res = [];
|
||||||
|
if (string.scanf(time, "%d:%d:%d:%d:%d:%d", var res1 = []) != 0) {
|
||||||
|
res = res1;
|
||||||
|
} elsif (string.scanf(time, "%d:%d:%d:%d:%d", var res2 = []) != 0) {
|
||||||
|
res = res2 ~ [0];
|
||||||
|
} elsif (string.scanf(time, "%d:%d:%d:%d", var res3 = []) != 0) {
|
||||||
|
res = res3 ~ [0, 0];
|
||||||
|
} elsif (string.scanf(time, "%d:%d:%d", var res4 = []) != 0) {
|
||||||
|
res = res4 ~ [0, 0, 0];
|
||||||
|
} elsif (string.scanf(time, "%d:%d", var res5 = []) != 0) {
|
||||||
|
res = res5 ~ [0, 0, 0, 0];
|
||||||
|
} elsif (string.scanf(time, "%d", var res6 = []) != 0) {
|
||||||
|
res = res6 ~ [0, 0, 0, 0, 0];
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return
|
||||||
|
(res[0] - 1970) * 3.15569e7 +
|
||||||
|
(res[1] - 1) * 2.63e+6 +
|
||||||
|
(res[2] - 1) * 86400 +
|
||||||
|
res[3] * 3600 +
|
||||||
|
res[4] * 60 +
|
||||||
|
res[5];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
## WildFire configuration dialog.
|
## WildFire configuration dialog.
|
||||||
## Partly based on Till Bush's multiplayer dialog
|
## Partly based on Till Bush's multiplayer dialog
|
||||||
|
@ -1126,7 +1189,7 @@ var dialog = {
|
||||||
#################################################################
|
#################################################################
|
||||||
select_and_load : func {
|
select_and_load : func {
|
||||||
var selector = gui.FileSelector.new
|
var selector = gui.FileSelector.new
|
||||||
(func (n) { CAFire.load_event_log(n.getValue()); },
|
(func (n) { load_event_log(n.getValue(), -1); },
|
||||||
"Load Wildfire log", # dialog title
|
"Load Wildfire log", # dialog title
|
||||||
"Load", # button text
|
"Load", # button text
|
||||||
["*.xml"], # pattern for files
|
["*.xml"], # pattern for files
|
||||||
|
|
Loading…
Reference in a new issue