Skip to content

Commit ef6faa2

Browse files
committed
Implement sensor, remove seekable_reader to fix panic when reading large processor config
1 parent 2234e0b commit ef6faa2

File tree

15 files changed

+614
-70
lines changed

15 files changed

+614
-70
lines changed

Cargo.lock

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ num-traits = "0.2.19"
1818
rand = "0.9.2"
1919
regex = "1.11.1"
2020
replace_with = "0.1.8"
21-
seekable_reader = "0.1.2"
2221
serde = { version = "1.0.219", features = ["derive"] }
2322
serde_json = "1.0.141"
2423
strum = "0.27.2"

src/logic/ast.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ pub enum Instruction {
4343
result: Value,
4444
index: Value,
4545
},
46+
Sensor {
47+
result: Value,
48+
target: Value,
49+
sensor: Value,
50+
},
4651
// operations
4752
Set {
4853
to: Value,

src/logic/grammar.lalrpop

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ match {
2121
"drawflush",
2222
"printflush",
2323
"getlink",
24+
"sensor",
2425
"set",
2526
"op",
2627
"select",
@@ -212,6 +213,9 @@ Instruction: Instruction = {
212213
"getlink" <result:Value> <index:Value> =>
213214
Instruction::GetLink { <> },
214215

216+
"sensor" <result:Value> <target:Value> <sensor:Value> =>
217+
Instruction::Sensor { <> },
218+
215219
// operations
216220

217221
"set" <to:Value> <from:Value> =>
@@ -468,6 +472,7 @@ Symbol = {
468472
"drawflush",
469473
"printflush",
470474
"getlink",
475+
"sensor",
471476
"set",
472477
"op",
473478
"select",

src/logic/vm/buildings.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use strum_macros::IntoStaticStr;
55
use super::{
66
LogicVMBuilder, VMLoadError, VMLoadResult,
77
processor::{Processor, ProcessorBuilder, ProcessorState},
8+
variables::LValue,
89
};
910
use crate::types::{
1011
Object, Point2, ProcessorConfig, SchematicTile,
@@ -93,6 +94,10 @@ impl Building {
9394

9495
_ => BuildingData::Unknown {
9596
config: config.clone(),
97+
senseable_config: match *config {
98+
Object::Content(content) => content.try_into().map(LValue::Content).ok(),
99+
_ => None,
100+
},
96101
},
97102
};
98103

@@ -180,7 +185,10 @@ pub enum BuildingData {
180185
Memory(Box<[f64]>),
181186
Message(Vec<u16>),
182187
Switch(bool),
183-
Unknown { config: Object },
188+
Unknown {
189+
config: Object,
190+
senseable_config: Option<LValue>,
191+
},
184192
}
185193

186194
impl BuildingData {

src/logic/vm/instructions.rs

Lines changed: 176 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use crate::{
1515
vm::variables::{F64_DEG_RAD, F64_RAD_DEG},
1616
},
1717
types::{
18-
ContentType, Point2, Team,
19-
colors::{f32_to_double_bits, f64_from_double_bits},
18+
ContentType, LAccess, Point2, Team,
19+
colors::{self, f32_to_double_bits, f64_from_double_bits},
2020
content,
2121
},
2222
};
@@ -87,7 +87,7 @@ impl Instruction for InstructionBuilder {
8787
var
8888
}
8989
}
90-
ast::Value::String(value) => LVar::Constant(LValue::String(value.into())),
90+
ast::Value::String(value) => LVar::Constant(LValue::RcString(value.into())),
9191
ast::Value::Number(value) => LVar::Constant(value.into()),
9292
ast::Value::None => LVar::Constant(LValue::Null),
9393
};
@@ -132,6 +132,15 @@ impl Instruction for InstructionBuilder {
132132
result: lvar(result),
133133
index: lvar(index),
134134
}),
135+
ast::Instruction::Sensor {
136+
result,
137+
target,
138+
sensor,
139+
} => Box::new(Sensor {
140+
result: lvar(result),
141+
target: lvar(target),
142+
sensor: lvar(sensor),
143+
}),
135144

136145
// operations
137146
ast::Instruction::Set { to, from } => Box::new(Set {
@@ -245,13 +254,15 @@ impl Print {
245254
n.to_string()
246255
})
247256
}
248-
LValue::String(s) => Cow::Borrowed(s),
257+
LValue::RcString(s) => Cow::Borrowed(s),
258+
LValue::StaticString(s) => Cow::from(*s),
249259
LValue::Content(content) => Cow::Borrowed(content.name()),
250-
LValue::Team(team) => team.name(),
260+
LValue::Team(team) => Cow::from(team.as_ref()),
251261
LValue::Building(position) => vm
252262
.building(*position)
253263
.map(|b| Cow::Borrowed(b.block.name.as_str()))
254264
.unwrap_or(Cow::from("null")),
265+
LValue::Sensor(sensor) => Cow::from(sensor.as_ref()),
255266
}
256267
}
257268
}
@@ -360,6 +371,166 @@ impl SimpleInstruction for GetLink {
360371
}
361372
}
362373

374+
struct Sensor {
375+
result: LVar,
376+
target: LVar,
377+
sensor: LVar,
378+
}
379+
380+
impl Sensor {
381+
fn sense_processor(sensor: LAccess, state: &ProcessorState) -> LValue {
382+
match sensor {
383+
LAccess::Enabled => state.enabled().into(),
384+
_ => LValue::Null,
385+
}
386+
}
387+
}
388+
389+
impl SimpleInstruction for Sensor {
390+
fn execute(&self, state: &mut ProcessorState, vm: &LogicVM) {
391+
use LAccess::*;
392+
393+
let target = self.target.get(state);
394+
let sensor = self.sensor.get(state);
395+
396+
let result = match sensor {
397+
// normal sensors
398+
LValue::Sensor(sensor) => match target {
399+
// dead
400+
LValue::Null if sensor == Dead => true.into(),
401+
402+
// senseable
403+
LValue::Content(content) => match content {
404+
// TODO: color, health, maxHealth, solid, powerCapacity
405+
Content::Block(block) => match sensor {
406+
Size => block.size.into(),
407+
ItemCapacity => block.item_capacity.into(),
408+
LiquidCapacity => block.liquid_capacity.into(),
409+
Id => block.logic_id.into(),
410+
Name => LValue::StaticString(&block.name),
411+
_ => LValue::Null,
412+
},
413+
414+
// TODO: color
415+
Content::Item(item) => match sensor {
416+
Id => item.logic_id.into(),
417+
Name => LValue::StaticString(&item.name),
418+
_ => LValue::Null,
419+
},
420+
421+
// TODO: color
422+
Content::Liquid(liquid) => match sensor {
423+
Id => liquid.logic_id.into(),
424+
Name => LValue::StaticString(&liquid.name),
425+
_ => LValue::Null,
426+
},
427+
428+
// TODO: health, maxHealth, size, itemCapacity, speed, payloadCapacity
429+
Content::Unit(unit) => match sensor {
430+
Id => unit.logic_id.into(),
431+
Name => LValue::StaticString(&unit.name),
432+
_ => LValue::Null,
433+
},
434+
},
435+
436+
LValue::Team(team) => match sensor {
437+
Name => LValue::StaticString(team.into()),
438+
Id => team.id().into(),
439+
Color => team.color().into(),
440+
_ => LValue::Null,
441+
},
442+
443+
LValue::Building(position) => match vm.building(position) {
444+
// TODO: solid, health, maxHealth, powerCapacity
445+
Some(building) => match sensor {
446+
X => building.position.x.into(),
447+
Y => building.position.y.into(),
448+
Color => colors::TEAM_SHARDED.into(),
449+
Dead => false.into(),
450+
Team => crate::types::Team::Sharded.id().into(),
451+
Efficiency => 1.into(),
452+
Timescale => 1.into(),
453+
Range => building.block.range.into(),
454+
Rotation => 0.into(),
455+
TotalItems | TotalLiquids | TotalPower => 0.into(),
456+
ItemCapacity => building.block.item_capacity.into(),
457+
LiquidCapacity => building.block.liquid_capacity.into(),
458+
PowerNetIn | PowerNetOut | PowerNetStored | PowerNetCapacity => 0.into(),
459+
Controlled => false.into(),
460+
PayloadCount => 0.into(),
461+
Size => building.block.size.into(),
462+
CameraX | CameraY | CameraWidth | CameraHeight => 0.into(),
463+
Type => Content::Block(building.block).into(),
464+
FirstItem => LValue::Null,
465+
PayloadType => LValue::Null,
466+
467+
_ => match building.data.try_borrow().as_deref().as_ref() {
468+
Ok(BuildingData::Processor(processor)) => {
469+
Self::sense_processor(sensor, &processor.state)
470+
}
471+
// if the building is already mutably borrowed, we're sensing @this
472+
Err(_) => Self::sense_processor(sensor, state),
473+
474+
Ok(BuildingData::Memory(memory)) => match sensor {
475+
MemoryCapacity => memory.len().into(),
476+
Enabled => true.into(),
477+
_ => LValue::Null,
478+
},
479+
480+
Ok(BuildingData::Message(buf)) => match sensor {
481+
BufferSize => buf.len().into(),
482+
Enabled => true.into(),
483+
_ => LValue::Null,
484+
},
485+
486+
Ok(BuildingData::Switch(enabled)) => match sensor {
487+
Enabled => (*enabled).into(),
488+
_ => LValue::Null,
489+
},
490+
491+
Ok(BuildingData::Unknown {
492+
senseable_config, ..
493+
}) => match sensor {
494+
Config => senseable_config.clone().unwrap_or(LValue::Null),
495+
Enabled => true.into(),
496+
_ => LValue::Null,
497+
},
498+
},
499+
},
500+
None => LValue::Null,
501+
},
502+
503+
// string length
504+
LValue::RcString(string) if matches!(sensor, BufferSize | Size) => {
505+
string.len().into()
506+
}
507+
LValue::StaticString(string) if matches!(sensor, BufferSize | Size) => {
508+
string.len().into()
509+
}
510+
511+
_ => LValue::Null,
512+
},
513+
514+
// if target doesn't implement Senseable, write null
515+
_ if !matches!(
516+
target,
517+
LValue::Content(_) | LValue::Team(_) | LValue::Building(_)
518+
) =>
519+
{
520+
LValue::Null
521+
}
522+
523+
// items/liquids aren't implemented, so always write null if sensing content
524+
LValue::Content(_) => LValue::Null,
525+
526+
// if target is Senseable and sensor isn't Content or LAccess, do not write to result
527+
_ => return,
528+
};
529+
530+
self.result.set(state, result);
531+
}
532+
}
533+
363534
// operations
364535

365536
struct Set {

0 commit comments

Comments
 (0)