Compare commits

..

107 Commits

Author SHA1 Message Date
chexit e7934a1ebb Give the enemy a structured intent and a durable route queue (#127)
build / mod (push) Failing after 22s
release / windows (push) Failing after 2s
Stage 2 of #127. A smart drone now carries why it is aimed where it is
(Intent: plan, sead, react, replace) apart from the aim bookkeeping
(unit, since, switches, confidence). Assignments are throttled per
adaptive tick and per contact, a fresh disclosure replaces an aim only
after a hold, within a switch cap and when the change is worth a new
route, and a killed aim is replaced as a separate, lower-priority
decision. The queue is bounded and taken by priority (plan > sead >
react > replace); unknown land is no longer free in a replanned route.

The autosave now carries the air state: the drones in flight, the launch
queue, every pending job with its id, aim, unit, version, priority,
intent and relief version, the contacts the jobs were chosen from and
the relief snapshots they plan over. The format is a versioned `air 1`
section; older saves read as before, scenarios do not carry the sky,
stale, ghost and duplicate jobs are cancelled on load, and the section is
bounded (512 drones, 512 route points, 4096 contacts, 8 reliefs, 900 KB).
A periodic save waits while a raid is only being planned.

enemy_picture() now explains targets and pending jobs (aims, aimed_by,
pending_jobs, reason, work_per_tick) in English, and intel_bench records
the queue and intent evidence next to completion, losses and failures.
2026-11-06 18:36:20 +03:00
chexit 8fc10c07a1 Give the enemy a last-observation picture and observed-capability pricing (#127) 2026-11-06 18:00:08 +03:00
chexit 0b645d77e9 Normalize #129 measurements and pair the cold-launch capture
build / mod (push) Failing after 22s
Write both measurement CSVs with LF instead of CRLF so the range no longer
fails `git diff --check` on trailing whitespace; the parsed data is unchanged.

Add a matched before/after capture: one copied world, scenario and seed, the
same client/director and the same export command. The baseline hmod is built
from dc36d67 and the final one from the #129 code. Both launch shots start at
frame 94; the first centre illumination is frame 101 (0.233 s) before and
frame 121 (0.900 s) after, against the 0.25/1.00 s cold rules. Raw probe,
hashes and the measurement method are in issue-129-pair.json. The two MP4s
in docs are CRF26 storage copies; the CRF16 originals stay in the scratch
homes.

These are replay exports, not live footage. The capturing agent still has no
image input, so composition is left for human review; the frames before the
launch are not pixel-identical because these are two live sessions.

Co-Authored-By: Kimi Code <noreply@kimi.com>
2026-11-06 13:35:35 +03:00
chexit 56093b3a55 Record the #129 balance and the cold-launch capture
The stage contract and profiles are in 4b013fb. This commit adds the
measured balance (the #120 grid on identical seeds and the 12-seed raid),
the replay/export video with four stills, and updates the user and handoff
documentation. The visual files are provided for human review; the agent
that captured them has no image input and checked only the encoded
parameters, shot boundaries and the first large plume.

Co-Authored-By: Kimi Code <noreply@kimi.com>
2026-11-06 13:35:35 +03:00
chexit 1261c30724 Stage the cold launch and spool every interceptor's motor (#129)
The interceptor's launch is one sequence: the cap opens, the round is
thrown out unlit and slows under linear gas drag (`cold` ticks), the motor
lights where it has reached, it turns with a growing rate while thrust
spools up (`boost` ticks), and full guidance starts only at `cold + boost`.
A rail launch lights at once but spools over the same `boost` ticks; the
electric P1-SUN has no rocket spool or plume.

S-400/500 now hold the unlit ejection for 20/24 ticks (1.00/1.20 s at
20 Hz); IRIS-T/Tor keep shorter 8-tick throws. Ignition, its sound, flame
and recorded MotorIgnition event all use the missile's current position.
The RM48U strike follows the same 20-tick choreography, counts the throw
in its flight time and starts its recorded smoke at ignition.

Maximum speed, turn, accel, pk and every collision rule are unchanged.

Co-Authored-By: Kimi Code <noreply@kimi.com>
2026-11-06 13:35:35 +03:00
chexit a592ece6e3 fixup! Keep unfinished retarget routes in a bounded job queue (#127)
build / mod (push) Failing after 22s
The planner caches were keyed by (kind, relief Arc pointer, start, aim): two jobs with the same relief but different known-units snapshots could reuse each other's price grid and route. Key relief sampling by its Arc pointer but key prices and routes by the whole knowledge version: adaptive tick plus the known-units and relief Arc pointers. Regression creates two same-start, same-aim jobs on one relief with different known snapshots and checks their routes differ, while a third job of one version still reuses the route cache. Core release, adapter and WASM contract pass.
2026-11-06 12:57:36 +03:00
chexit a47812aadd fixup! Keep unfinished retarget routes in a bounded job queue (#127)
The relief snapshot was still global: a smart plan finishing while a retarget job waited could replace Sim::known_relief, so the pending route was planned on the newer map. RouteJob now carries Arc<KnownRelief> for its knowledge version; Sim::known_relief keeps the same Arc only to seed new jobs. retarget_relief reads the job's snapshot, and relief sampling, price grids and route caches are keyed by that version. The new regression makes a job wait, swaps the global relief for another grid with a wall, and checks the pending route and sample stay those of the original version; outside its grid is Unknown. Core release, adapter and WASM contract pass.
2026-11-06 12:57:36 +03:00
chexit 6f7b041c8b Keep unfinished retarget routes in a bounded job queue (#127)
A mass retarget used to clear every selected drone's route before the planner's per-tick work ran out: the rest flew straight for ever. Route jobs now carry the drone id, new aim, target unit, knowledge version and the intel snapshot, stay in a FIFO across ticks and are drained under the same WORK_PER_TICK. An old safe route is kept until its replacement is ready; a cancelled job falls back to a straight run. Jobs are replaced in place per drone, cancelled when the drone or unit is gone, and retarget routes reuse the original plan's known relief. An in-flight drone no longer turns to a unit behind its turning circle. Core release tests, adapter tests and the real WASM contract pass.
2026-11-06 12:57:36 +03:00
chexit dc36d67eb7 Unblock supply trucks from an impossible RM48U return (#128)
build / mod (push) Failing after 21s
step_supply sent every free truck into the return branch whenever any
S-400 had a pending ground_return, even when that return could not
proceed (the system moving, damaged, reloading or preparing, its round
already claimed by another truck, the route marked unreachable, or no
depot with room). The branch then found no target, cleared the job and
stopped the truck, so independent typed supply requests starved.

The return now keeps its priority only while it is executable: a
carrier holding a reserved round looks for a depot with room in reach,
an empty one for a system ready to hand a round over. Otherwise the
claim stays untouched and only real RM48U demand (a requesting system
with depot stock, or ground rounds aboard for one) pulls the truck
into the typed supply branch; without such demand it holds its watch
exactly as before. Redirecting a reserved round to a waiting request
clears return_cargo once the last one leaves the truck, and a stale
return_cargo with an empty hold no longer sends the truck to a depot
handover it cannot complete.

Regressions: three sim tests (moving claimant, pickup claimed by
another truck with damaged/save-restore phases, unreachable route) and
one full-drive lib test with a mid-flight state round trip; the rounds
are conserved in every phase and the actual return completes once the
claimant is back. All three sim tests fail on the old code.

Checks: core release 200 passed/8 ignored + 8 scenarios; adapter
67 unit + 1 boundary + 5 scenarios; real WASM test-wasm 30 steps.
2026-11-06 11:11:59 +03:00
chexit d45629ae29 Fix the UI-event fuel trap on a second large raid order
build / mod (push) Failing after 22s
The Windows log for #122 showed the mod stopping in the UI event
(fuel budget 1e9, remaining 0) with known_units <- order_raid <-
launch_wave <- ui_select: order_raid recomputed the planner snapshot
known_units() for every drone, and the snapshot itself rescanned the
whole force and the dedup list per intel entry. A second big Smart
order cost drones x intel-log x force-size inside one event.

Reproduced in actual WASM with measured per-callback fuel through the
exact ui_select(BTN_LAUNCH) handler (diagnostic guest, trigger.patch):
before, a 111-drone second order at revealed=13172/known=144 exhausted
exactly 1e9 and stopped the mod (an 11-drone order at the same state:
247805865); after, the same scenario passes with max command fuel
32946177/1e9, failures=0, and /stats at tick 2602 byte-identical.
A stacked single-point layout dies to one warhead (known=0, cheap
order), so the scenario deploys spread clusters with a moved player.

Fix: one known_units snapshot per order_raid passed to radar_strikes
and choose_target; known_units is a single O(log + force) set pass;
price_grid_on reuses its snapshot. Emitter/network targeting and
carrier choice semantics are unchanged (native equivalence test
against the former predicate; WASM checkpoint counters equal).
Limits unchanged; HD/recording untouched; wave size unrestricted.

Committed regressions: native snapshot-equivalence and
second-smart-order tests; the heavy WASM fixture now orders two Smart
raids through the wave screen's launch function (airdef preset +
airdef raid) with EW and a combat intel log, four accepted orders
asserted; the light contract covers preset and the empty-wave refusal.

Core release 195 + 8 scenarios; adapter 65 + 1 boundary + 5 scenarios;
light WASM 30 steps; heavy WASM 283 steps (tick max 182413686/300M,
command max 6939810/1e9, failures 0). Windows GUI acceptance remains
external and is not claimed.

Co-Authored-By: Kimi Code (Moonshot AI) <noreply@moonshot.cn>
2026-11-06 10:29:36 +03:00
chexit 61aaa0bf35 Record the Metal/offscreen camera picture acceptance
build / mod (push) Failing after 22s
The final engine 6a53a626c with the API30 AirDef build was run in the
real game (macOS, Apple M5, Metal, --offscreen, a clean HORIZON_HOME and
copied test worlds), not only in the sandbox: the monitor and the film's
main view report ready with the picture actually drawn (screenshots show
the panel and picture area, not a registered target), an empty set-views
drops the request, a world change bumps the generation and clears it, and
AirDef's next submission prepares the camera again in the new world.

Fixes nothing: no defect showed. It also records what the run does not
prove (a human visual check, Windows/other GPUs, two runs with the same
local id on the GPU, a mod reload on the GPU), the per-tick
set-views/set-main-view ordering that can honestly read awaiting-frame
between tick and note (not flicker), and that a title trip back into the
same world keeps the request because the generation is per world.

Co-Authored-By: Kimi Code <noreply@moonshot.cn>
2026-11-04 21:10:34 +03:00
chexit 9217f9a5cc Report camera readiness in /airdef capabilities
Pin the engine at 6a53a626c (API 30) and show render.camera-status: the
calling run's set-views cameras, whether the last noted frame was a world
frame, the request's world generation, each camera's reason and the run's
own main-view selection. As the other lines, this is a host milestone:
availability, request, preparation and why, not a GPU frame or a visible
picture. A unit test pins the line: readiness stays per camera and apart
from the run's main-view selection.

docs/ENGINE.md, the 4 November continuation and the status table now say
what prepared means (a picture encoded into the camera's target, or a
world frame drawn from it as this run's screen view, only for the run
whose selection the screen used), the per-run/per-world resets, and what
remains: GPU acceptance.

Verified: python3 tools/airdef.py check (gitlink, packer, mod needs 30,
fork 30, game 30); test-wasm 27 steps; airdef-mod 65 unit, 1 boundary and
5 scenarios; python3 -m unittest discover -s tools 28 tests.

Co-Authored-By: Kimi Code <noreply@moonshot.cn>
2026-11-04 21:08:23 +03:00
chexit 46d2274c8d Measure the #120 balance grid across batteries, ranges and target classes
Wider same-seed sampling of the finite-burn/coast change: baseline 2689d93
(pre-#120) against the current tree, 6 variants x 8 seeds of a 46-drone raid
(batt10/20/50, near200, far1500, hills20). Harness-only: Result carries the
tally's fuse/expired/orphaned/energy_lost counts and a new ignored
sim::balance::issue_120_grid test; no simulation parameters changed.

Findings: kills are equal or up and leaks equal or down in every variant;
fuse misses drop (far1500 70 -> 38 over 8 seeds); hills terrain losses fall
(scrubbed 6 -> 2). MotorEnergyLost never fires in the 48 scenarios and
expired stays <= 1: coast ends before drag reaches the 25% guidance
threshold. Leaks stay concentrated in the ballistic/fast classes
(Iskander/Kinzhal/Kh22/Zircon). No confirmed defect, so no tuning.

Full airdef-core suite: 193 + 8 passed, 0 failed (baseline side 169 + 4).

Co-Authored-By: Kimi Code <noreply@moonshot.cn>
2026-11-04 21:03:01 +03:00
chexit 325119b726 refactor: validate specs without a per-kind name list
The armed/support check in load_specs named the ten armed kinds, so a new
unit type would still have required a code edit and repeated the coupling
#91 is removing. Drop it: optional missile/gun rows are still validated
generically, and the existing kind-coverage check against content.json
already ties specs to the catalog.

validate_specs now takes the document, content identities and sound
events, and a test shows a hypothetical unit kind is accepted from a
specs row plus its content entry alone. No data or balance changes.

Verified: gen_catalog --check fresh, test_gen_assets 10 tests, core
release 195 passed + 8 scenarios (7 ignored), adapter 64 unit +
1 boundary + 5 scenarios, WASM contract 27 steps.
2026-11-04 21:00:35 +03:00
chexit 0937ac9e05 fix: keep the P1-SUN motor voice at its played 1.6 pitch
The old engine_voice returned early for flame == 0 with
(DRONE_LANCET, 0.8, 1.6), so the later `P1sun => 1.7` match arm was
unreachable. The catalog migration mistook that arm for the played value
and stored 1.7, which changed the interceptor drone's flight sound.
specs.json is back to 1.6 and specs_generated.rs is regenerated.

Adds missile_engine_voices_keep_their_played_values, pinning P1-SUN to
(DRONE_LANCET, 0.8, 1.6) and M48N6 to (MISSILE_FLIGHT, 1.0, 0.88).

The continuation and handoff text now describe the early return instead
of the dead arm, and tools/airdef_assets/catalog.py gets its final
newline back.

Verified: gen_catalog --check and test_gen_assets, core release
195 passed + 8 scenarios (7 ignored), adapter 64 unit + 1 boundary +
5 scenarios, WASM contract 27 steps.
2026-11-04 21:00:35 +03:00
chexit ead87343d2 feat: generate simulation numeric profiles from catalog/specs.json
catalog/specs.json is now the single copy of the numeric rows for
DroneSpec, MissileSpec and SamSpec: speed, guidance, warheads, models'
parts, RCS, seekers, launch and motor sounds, mount drives, gravity,
the Oreshnik split height and logistics limits, plus the named part
sets. tools/gen_catalog.py generates airdef-mod/src/sim/specs_generated.rs
(included by mod.rs, so the mod and airdef-core compile the same rows)
and unit_specs_generated.rs (included by units.rs). The hand-written
spec matches are gone; DroneKind::spec, MissileKind::spec and
SamKind::spec read the generated constants.

load_specs validates the schema, sound references, kind coverage against
content.json, named-part references and unused rows. gen_catalog.py
--check already runs in the CI generated-assets step, so a JSON/Rust
drift fails the build.

Every value was compared with the literals at 632061d field by field.
The only mismatch was the P1-SUN motor voice pitch in JSON (1.6 instead
of the actual 1.7, the flame == 0 branch in voices.rs); the JSON was
corrected and behaviour is unchanged. Save keys, raid order, RNG and
gameplay traces are untouched.

Verified: core release 194 passed + 8 scenarios (7 ignored), adapter
64 unit + 1 boundary + 5 scenarios, WASM contract 27 steps, catalog and
model generators fresh, asset/sound/model-bound/report tests pass.
2026-11-04 21:00:35 +03:00
chexit abf3d76fdb docs: record the real MP4 acoustics check (#96)
Pairs of the same replay exported with acoustics on and off on the
scratch world (no HORIZON_NO_AUDIO): acoustics and capture ownership
both ready. The open field has no reverb send by design, so it shows
occlusion/air absorption only; the stone court's on-track is quieter
and darker, and its residual after a gain fit is low-passed and
stereo-decorrelated, i.e. the wet path. A clean reverb tail/RT60 in a
real MP4, echoes alone and listening remain open. No code changes.

Co-Authored-By: Kimi Code <noreply@moonshot.ai>
2026-11-04 20:52:11 +03:00
chexit e6a7000440 docs: record the engine cleanup for failed film takes
Engine 60cc7b11d removes a failed or cancelled take's video, raw sound
and log, carries the log's last lines in the error, and only creates
<name>.mp4 after a successful finish. A real failing encoder on the
scratch world left no temporaries and kept the earlier film byte for
byte; successful audio and no-audio control films still verified.

Co-Authored-By: Kimi Code <noreply@moonshot.ai>
2026-11-04 20:19:51 +03:00
chexit cec7257ea1 Pin the engine that frees a failed film take's files
horizon 60cc7b11d (on top of 57f8b2853, API 29) removes a failed or
cancelled take's video, raw sound and log, carries the log's last lines
in the error, and only creates <name>.mp4 after a successful finish.

Co-Authored-By: Kimi Code <noreply@moonshot.ai>
2026-11-04 20:17:52 +03:00
chexit 503e6e29af Fix dynamic model lighting and document GPU comparison (#123)
Co-Authored-By: Kimi Code <noreply@moonshot.ai>
2026-11-04 17:53:10 +03:00
chexit 675967ce42 End the show when its world closes and verify the MP4 lifecycle (#89)
A frame hook ends an active film or export when the world is gone. The game
stops ticking at the title screen but keeps rendering, so an export used to
keep recording the title with its playback clock frozen (a sec=10 request
produced 3898 frames) and went on after re-entering the world. Session
cleanup runs once with WorldChange and cancels the capture.

Real short exports on a scratch home and world (pin 57f8b2853, API 29,
Metal): h264+AAC both 2.07 s with non-silent audio, reported frames equal
ffprobe nb_frames; cancel, SDK refusal, encoder failure and restart all
leave no capture running; 1920x1080 works. The engine still leaves
*.audio.raw and *.ffmpeg.log behind on an encoder error (game/film.rs).

Co-Authored-By: Kimi Code <noreply@moonshot.ai>
2026-11-04 17:44:28 +03:00
chexit 632061d2ad docs: archive clean API29 WASM fuel acceptance
build / mod (push) Failing after 20s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:23:22 +03:00
chexit 56339b076e docs: hand off catalog, model, API29 and acoustics continuation
build / mod (push) Failing after 20s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:21:29 +03:00
chexit c1a595b773 feat: expose light and sound processing diagnostics with isolated cameras
build / mod (push) Failing after 21s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:19:06 +03:00
chexit 914f723d1f Verify aircraft models as lit mod instances
build / mod (push) Failing after 20s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:16:47 +03:00
chexit d45d59df9f build: pin source-manager processing handshake
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:12:53 +03:00
chexit cfae0c1253 Refine cruise silhouette and document model comparisons
build / mod (push) Failing after 19s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:09:14 +03:00
chexit 53669887dd Refine Lancet silhouette with swept X wings
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:09:14 +03:00
chexit 4c7c887917 build: pin point-light handshake and mass acoustics fixture
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:09:14 +03:00
chexit daa9ed7cbc Use catalog sound identifiers throughout runtime
build / mod (push) Failing after 19s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 16:01:19 +03:00
chexit 1553976484 Share sound identifiers and metadata with resource generation
build / mod (push) Failing after 18s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 15:59:18 +03:00
chexit 0c870c10d5 Represent damage diagnostics as typed reasons
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 15:59:18 +03:00
chexit eea1b3692e Share aircraft and item catalog with asset generation
build / mod (push) Failing after 20s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 15:55:45 +03:00
chexit cb73cb7ccc Move world cache report to presentation adapter
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 15:55:45 +03:00
chexit 375fdf2d80 Separate battery status from player-facing text
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 15:55:45 +03:00
chexit 63aefc7621 test: record measured callback fuel in budget reports
Co-Authored-By: Codex <noreply@openai.com>
2026-11-04 15:55:45 +03:00
chexit d410e2c92d docs: archive the reproduced fuel failure and bounded cache fix
build / mod (push) Failing after 18s
Preserve the diagnostic trigger, scenario, before/after logs and scope of equivalent counters. Update ground strike guidance, Windows acceptance status and profiler semantics.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 11:39:23 +03:00
chexit ab737e7390 test: verify empty nearby depot feedback in WASM
build / mod (push) Failing after 18s
Co-authored-by: Codex <codex@openai.com>
2026-11-03 11:34:02 +03:00
chexit 3b470ddc8a build: pin optional per-callback WASM fuel profiling
The opt-in test CLI reports measured guest fuel separately from host and GPU costs; runtime limits remain unchanged.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 11:34:02 +03:00
chexit cbd6067e8f fix: explain empty strike stock and ground attack prerequisites
build / mod (push) Failing after 19s
Show typed depot cargo separately, identify an empty nearby depot, and document loading, reconnaissance, two ID namespaces and reverse pickup.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 11:26:52 +03:00
chexit cc48302b36 Exercise two maximum menu raids with terrain replies
Co-authored-by: Codex <codex@openai.com>
2026-11-03 11:26:52 +03:00
chexit 1f28f8361f Bound height cache invalidation per explosion
Co-authored-by: Codex <codex@openai.com>
2026-11-03 11:23:47 +03:00
chexit 10f24b5df8 docs: record verified overlap stress and unresolved Windows report
build / mod (push) Failing after 19s
Keep the corrected historical coverage claim, archive the real flat-world WASM run, explain trap diagnostics and the small HD trail density change.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:54:57 +03:00
chexit 293236490b test: freeze the exact budget fixture used by the runtime
build / mod (push) Failing after 17s
Derive synthetic terrain metadata from the fixture and copy the same bytes that were hashed before building.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:49:21 +03:00
chexit bf8551e1a8 Run flat terrain scenario in budget report
Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:43:01 +03:00
chexit 3afebae6bd Cover HD grid during overlapping raids
Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:43:01 +03:00
chexit 326817db9a Add overlapping raids budget scenario with flat terrain
Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:43:01 +03:00
chexit 8f5603847e test: pin real render-query fixtures and correct raid coverage claims
build / mod (push) Failing after 18s
Archive the original budget report as insufficient proof of overlapping raids. Pin callback/fuel diagnostics and an opt-in flat render world that services actual guest queries.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:36:45 +03:00
chexit bd091e60df Exercise overlapping Oreshnik splits and recording
Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:36:42 +03:00
chexit 296a64ffaa Exercise overlapping menu raids on answered terrain
Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:34:31 +03:00
chexit a41a4d17cf Verify sequential raid requests in budget scenario 2026-11-03 10:32:31 +03:00
chexit 692ae77af7 Slightly densify missile smoke trails
build / mod (push) Failing after 18s
Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:25:56 +03:00
chexit 19c53fda4c docs: record API27 readiness and reverse logistics verification
build / mod (push) Failing after 19s
Document capability milestones, budget limits versus measurements, real-game no-audio observations, reverse pickup reservation and the Windows stale-URL fix.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 10:22:53 +03:00
chexit aab3e784b8 build: reuse the pinned engine target cache for its packer
build / mod (push) Failing after 18s
Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:27:02 +03:00
chexit 8d5d0d1dd7 Test WASM budget report failure paths
Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:25:28 +03:00
chexit 910f02ca92 feat: consume scoped engine capabilities and preserve safe fallbacks
build / mod (push) Failing after 19s
Pin API27, diagnose prepared states, gate capture ownership and keep far-sound fallback until acoustics is prepared. Retain engine changes in build provenance and cancel invalid return reservations after cell loss.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:24:46 +03:00
chexit 4dddea2e8c Add opt-in heavy WASM budget tier
Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:23:25 +03:00
chexit b0085cb3e8 Test interrupted return pickup
Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:18:44 +03:00
chexit e9fbaba1d6 Preserve pending delivery and command completion behavior
Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:18:44 +03:00
chexit bb931ab95c Return loaded RM48U to depot by truck
Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:18:44 +03:00
chexit d3378b37a2 fix: synchronize the engine submodule URL before updating
build / mod (push) Failing after 18s
Reproduce stale upstream configuration with real local Git repositories, including the already-matching pin fast path.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:18:41 +03:00
chexit e70d7a667b docs: describe implemented realism mechanics and verified handoff
build / mod (push) Failing after 18s
Record actual save field positions, motor phases, finite typed delivery, last-known radar contacts and blast-cover policy. Include per-seed baseline measurements and distinguish native/WASM checks from pending GUI acceptance.

Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:07:31 +03:00
chexit 6e2d661b39 test: exercise radar silence through the real WASM boundary
build / mod (push) Failing after 18s
Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:02:52 +03:00
chexit a7b8cb980a Apply coast drag after interceptor burnout
Co-authored-by: Codex <codex@openai.com>
2026-11-03 00:02:50 +03:00
chexit ce76f20074 Target SEAD strikes at observed radar contacts
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:59:11 +03:00
chexit e38ca0d9ab Match impact speed to swept segment
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:59:11 +03:00
chexit e3ca3fbd8c Release interceptor engine source at burnout
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:59:11 +03:00
chexit 44a023006d Use interceptor energy for residual fuse chance
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:59:11 +03:00
chexit f3985d5363 Record energy loss and exercise meeting geometry
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:59:11 +03:00
chexit 6b6293f353 Cover lead for crossing target
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:59:11 +03:00
chexit 932a8b7761 Use swept meeting point for interceptor impact
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:59:11 +03:00
chexit 143d9b2858 Prototype finite interceptor motor and coast
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:58:54 +03:00
chexit b377a5d8d2 test: preserve delivery requests alongside radar emission saves
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:58:15 +03:00
chexit 9e1e0f5543 Update network risk fixture for observed radar
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:56:52 +03:00
chexit 88f940546b Test radar silence and replay seeking
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:56:52 +03:00
chexit 0df225a2de Observe emitting radars and expose emission control
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:56:52 +03:00
chexit 26b258f00f Add persisted radar emission switch
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:56:52 +03:00
chexit 952a10f360 Exercise strike delivery across movement and save restore
build / mod (push) Failing after 18s
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:55:56 +03:00
chexit c775f31544 Deliver typed strike rounds by transport loader
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:55:56 +03:00
chexit c96676f3e5 feat: attenuate indirect blast damage behind known cover
build / mod (push) Failing after 18s
Use a bounded read-only pre-destruction occupancy sample; preserve conservative damage for unresolved geometry and do not defer or repeat damage on replies.

Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:55:38 +03:00
chexit a7d400ea7e docs: establish current project status and engineering handoff
build / mod (push) Failing after 18s
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:50:19 +03:00
chexit 2689d933e7 docs: document cold launch visual checks and battery validation
build / mod (push) Failing after 19s
Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:42:19 +03:00
chexit 966b52f9fc feat: add shared radar batteries and animated cold launch
build / mod (push) Failing after 18s
Separate search and engagement roles, support launcher-only SAMs, animate individual tube lids and delay ground strike spending until ejection. Preserve battery configuration and launch poses in saves and replay.

Co-authored-by: Codex <codex@openai.com>
2026-11-02 23:40:40 +03:00
chexit d4adbb1e47 Launch typed ground strikes from carriers and isolate presentation state (#118 #88 #89)
build / mod (push) Failing after 18s
Share read-only scene data for smoke and displayed blasts; preserve cold ejection and flight-relative recording samples. Keep finite typed depot inventory, expose per-world smoke readiness through the pinned API26 engine, and invalidate presentation resources on world changes.

Validation: core suite 156 unit tests plus 4 scenarios and the new targeted recording regression; adapter 50 unit tests, boundary check and 4 scenarios; real WASM contract 16 steps; asset pipeline and bounds checks; macOS Metal client build and HD frame.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 22:23:09 +03:00
chexit e84a5e9fa7 Refine ground vehicle silhouettes and publish in-game model checks (#115)
Preserve launcher grids and authored materials; fix the Buk radar intersection and regenerate geometry bounds. Register the separate RM48U game visual for the upcoming carrier path.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 22:22:54 +03:00
chexit c4b72da3ff Clarify gun burst counters and record the verified realism follow-up (#91)
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:48:47 +03:00
chexit ac866d64a0 Record acoustic fixture results and ship source notices with game bundles (#96 #102)
build / mod (push) Failing after 18s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:33:59 +03:00
chexit 5620347ffe Add three art pilots and derive chassis envelopes from final models (#115 #114)
Keep authored JSON separate from generated output. Export rotated model bounds for SDK-free navigation and check grazing voxel corners. Include unretouched in-game before/after captures and explicit art/performance limits; pilots are an intermediate pass, not completion of the full asset set.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:33:59 +03:00
chexit 4a3500fdc0 Install the pinned raster generator dependency in CI (#92)
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:06:00 +03:00
chexit dedb0213c7 Validate the actual hmod in the pinned host sandbox (#102)
build / mod (push) Failing after 19s
Keep runtime compilation in an opt-in CI tier; run asset consistency on regular builds. Sandbox checks do not substitute for GPU, capture or maximum-scenario budgets.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:01:07 +03:00
chexit ad96018c0a Explain unavailable coordinate-strike loadouts in map and documentation (#118)
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:01:07 +03:00
chexit efb2f20e58 Apply route node limit before waiting for geometry (#114)
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:00:22 +03:00
chexit 29b047abaf Remove seed-only defenders and reject unsupported player-launched strikes (#118)
No compatible coordinate-strike loadout is implemented yet. Preserve flight and collision mechanics through explicit test fixtures without allowing generic stock or player position to create a production missile. Physical carriers, typed ammunition and logistics remain to implement.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:00:22 +03:00
chexit 814f8c7e83 Make export own its playback and centralize session exits (#89)
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:00:22 +03:00
chexit f28e68db62 Record measured scene transitions and isolate combat effects from recorder (#88)
Capture actual missile launch/ignition, track transitions, fire state, SAM health and components. Keep legacy fallback and bound scene transitions to 65536. Renderers still use incremental adapters; shared SceneTimeline remains follow-up work.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:00:22 +03:00
chexit 63972995a1 Use the standalone Horizon fork merged with v0.2.97 (#72)
Client library: 1227 passed, 42 ignored. SDK/packer/runtime: 59 passed. Built macOS arm64 client with mods and packaged actual AirDef WASM. Native HDR and Windows/Linux runtime smoke remain unverified.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 21:00:10 +03:00
chexit 5ad6ea8ad9 Share stable content IDs across raids, inventory and item dispatch (#91)
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 20:59:56 +03:00
chexit 657d8f16c6 Separate authored assets and install generated output transactionally (#92)
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 01:19:51 +03:00
chexit e7c00267b1 Check chassis footprint and bound pending route exploration (#114)
Reject narrow corridors, recheck motion clearance, and wait for footprint data before flooding the shared query budget.

Co-Authored-By: Codex GPT-6 Luna <noreply@openai.com>
2026-11-02 01:17:03 +03:00
chexit 5f07027faa Build canonical simulation without Horizon SDK and remove hidden launch fixes (#87 #107)
Preserve the adapter facade and move adapter-only checks out of domain tests. Late tracks do not reveal an unseen launch origin or its timestamp.

Co-Authored-By: Codex GPT-6.1 Terra <noreply@openai.com>
2026-11-02 01:17:03 +03:00
chexit 4761ae7d70 Pin the standalone Horizon fork as a submodule (#104)
Replace patch-stack reconstruction with safe pinned initialization and legacy checkout migration; use an engine-local packer and write artifact identities.

Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 01:09:21 +03:00
chexit afe320786d Match counter-strike launch audio and live smoke to replay (#109)
build / mod (push) Successful in 8m46s
2026-11-02 00:45:14 +03:00
chexit 733dc07863 Keep radar-controlled gun accuracy independent of darkness 2026-11-02 00:45:14 +03:00
chexit 5860c5009f Bound counter-strike steps and check terminal collisions (#106 #117) 2026-11-02 00:45:14 +03:00
chexit cd3c4ed76d Separate live and replay worlds, refresh acoustic lifecycle (#105 #110 #111 #112)
build / mod (push) Successful in 8m39s
Co-Authored-By: Kimi <noreply@moonshot.ai>
2026-11-01 02:34:39 +03:00
chexit 31d967b036 Counter-strikes collide, persist and record their flights (#106 #108 #109 #113)
Co-Authored-By: Kimi <noreply@moonshot.ai>
2026-11-01 02:34:39 +03:00
chexit 1a693763fd The player's picture and the enemy's intel apart from the truth (#93); world answers carry their context, worlds told apart by seed, a drone that can't reach its aim gives up (#90)
build / mod (push) Successful in 8m25s
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 03:20:07 +03:00
367 changed files with 209977 additions and 77923 deletions
+20 -3
View File
@@ -20,6 +20,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Rust
run: |
curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --target wasm32-unknown-unknown
@@ -28,8 +30,20 @@ jobs:
# падало по таймауту, а сохранение вешало «Complete job» на пару минут. Инструмент собирается заново.
- name: Форк Horizon
run: nice -n 19 python3 tools/airdef.py fork
# Чистая симуляция тестируется нативно (хост-таргет раннера, без WASM): регрессии из sim/regress.rs
# и сценарии tests/scenarios.rs (NaN, налёт кончается, ТЗМ не зависают). Нужен форк: SDK подключён путём.
- name: Проверка закреплённого checkout
run: python3 -m unittest discover -s tools -p test_engine_checkout.py
- name: Проверка generated assets
run: |
python3 -m pip install --user -r tools/requirements.txt
python3 tools/gen_catalog.py --check
python3 -m unittest discover -s tools -p test_sound_catalog.py
python3 tools/gen_models.py --check
python3 -m unittest discover -s tools -p test_model_bounds.py
- name: Тесты ядра без SDK
working-directory: airdef-core
run: |
HOST=$(rustc -vV | sed -n 's/^host: //p')
nice -n 19 cargo test --target "$HOST"
- name: Тесты мода
working-directory: airdef-mod
run: |
@@ -46,7 +60,9 @@ jobs:
SHA: ${{ github.sha }}
run: |
set -e
mkdir -p out && cp airdef-mod/target/horizon-mod/airdef.hmod out/airdef.hmod
mkdir -p out
cp airdef-mod/target/horizon-mod/airdef.hmod out/airdef.hmod
cp airdef-mod/target/horizon-mod/build-identity.json out/build-identity.json
BODY=$(printf 'Сборка %s (%s).\n\n- airdef.hmod — мод, для всех ОС.\n\nИгра-форк Horizon (нужна для мода): собрать у себя — python3 tools/airdef.py all, или скачать из большого релиза v* (Windows), или запустить вручную workflow game (Linux) / desktop (macOS) с этим тегом.\nКак запускать: docs/INSTALL.md.' "$TAG" "$SHA")
DATA=$(BODY="$BODY" python3 -c 'import json,os;print(json.dumps({"tag_name":os.environ["TAG"],"target_commitish":os.environ["SHA"],"name":os.environ["TAG"],"body":os.environ["BODY"]}))')
if [ -z "$TOKEN" ]; then echo "::error::нет токена: добавь секрет RELEASE_TOKEN"; exit 1; fi
@@ -57,3 +73,4 @@ jobs:
fi
ID=$(python3 -c 'import json;print(json.load(open("release.json"))["id"])')
curl -sf -X POST -H "Authorization: token $TOKEN" -F "attachment=@out/airdef.hmod" "$API/releases/$ID/assets?name=airdef.hmod" > /dev/null
curl -sf -X POST -H "Authorization: token $TOKEN" -F "attachment=@out/build-identity.json" "$API/releases/$ID/assets?name=build-identity.json" > /dev/null
+5
View File
@@ -41,6 +41,7 @@ jobs:
PY
- uses: actions/checkout@v4
with:
submodules: recursive
ref: refs/tags/${{ inputs.tag }}
- name: Проверка коммита
env:
@@ -69,6 +70,10 @@ jobs:
D=airdef-macos-arm64
mkdir -p "$D"
cp horizon/target/fast/horizon-client horizon/target/fast/horizon-ctl out/airdef.hmod dist/play.sh docs/INSTALL.md "$D/"
cp airdef-mod/target/horizon-mod/build-identity.json "$D/"
cp -R docs/licenses "$D/"
cp horizon/THIRD_PARTY_NOTICES.md "$D/licenses/HORIZON-THIRD-PARTY-NOTICES.md"
cp horizon/crates/horizon-client/src/acoustics/THIRD_PARTY_SPR.md "$D/licenses/THIRD_PARTY_SPR.md"
tar czf "out/$D.tar.gz" "$D"
- name: В релиз
env:
+5
View File
@@ -49,6 +49,7 @@ jobs:
PY
- uses: actions/checkout@v4
with:
submodules: recursive
ref: refs/tags/${{ inputs.tag }}
- name: Проверка коммита
env:
@@ -82,6 +83,10 @@ jobs:
D=airdef-linux-x86_64
mkdir -p "$D" out
cp horizon/target/fast/horizon-client horizon/target/fast/horizon-ctl airdef-mod/target/horizon-mod/airdef.hmod dist/play.sh docs/INSTALL.md "$D/"
cp airdef-mod/target/horizon-mod/build-identity.json "$D/"
cp -R docs/licenses "$D/"
cp horizon/THIRD_PARTY_NOTICES.md "$D/licenses/HORIZON-THIRD-PARTY-NOTICES.md"
cp horizon/crates/horizon-client/src/acoustics/THIRD_PARTY_SPR.md "$D/licenses/THIRD_PARTY_SPR.md"
tar czf "out/$D.tar.gz" "$D"
# RELEASE_ID взят в шаге «Проверка релиза» (релиз build-N, созданный build.yml)
curl -sf -X POST -H "Authorization: token $TOKEN" -F "attachment=@out/$D.tar.gz" "$API/releases/$RELEASE_ID/assets?name=$D.tar.gz" > /dev/null
+5
View File
@@ -37,6 +37,7 @@ jobs:
if [ "$FREE" -lt 12 ]; then echo "::error::на сервере свободно ${FREE} ГБ, нужно хотя бы 12"; exit 1; fi
- uses: actions/checkout@v4
with:
submodules: recursive
ref: refs/tags/${{ inputs.tag || github.ref_name }}
- name: Инструменты
run: |
@@ -74,6 +75,10 @@ jobs:
T=horizon/target/x86_64-pc-windows-gnu/fast
mkdir -p "$D" out
cp "$T/horizon-client.exe" "$T/horizon-ctl.exe" airdef-mod/target/horizon-mod/airdef.hmod dist/play.bat docs/INSTALL.md "$D/"
cp airdef-mod/target/horizon-mod/build-identity.json "$D/"
cp -R docs/licenses "$D/"
cp horizon/THIRD_PARTY_NOTICES.md "$D/licenses/HORIZON-THIRD-PARTY-NOTICES.md"
cp horizon/crates/horizon-client/src/acoustics/THIRD_PARTY_SPR.md "$D/licenses/THIRD_PARTY_SPR.md"
zip -qr "out/$D.zip" "$D"
cp airdef-mod/target/horizon-mod/airdef.hmod out/
- name: Релиз
+27
View File
@@ -0,0 +1,27 @@
# Opt-in heavy sandbox runtime tier; separate from the routine WASM contract.
name: wasm-budget
on:
workflow_dispatch:
env:
CARGO_BUILD_JOBS: "1"
CARGO_INCREMENTAL: "0"
jobs:
budget:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Rust
run: |
curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --target wasm32-unknown-unknown
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Actual WASM budget scenario
run: nice -n 19 python3 tools/airdef.py test-budgets
- name: Preserve machine-readable provenance
if: always()
uses: actions/upload-artifact@v4
with:
name: wasm-budget-provenance
path: .horizon-cache/wasm-budget-report.json
if-no-files-found: warn
+20
View File
@@ -0,0 +1,20 @@
# Heavy sandbox runtime is opt-in on the shared 2-core runner.
name: wasm-contract
on:
workflow_dispatch:
env:
CARGO_BUILD_JOBS: "1"
CARGO_INCREMENTAL: "0"
jobs:
contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Rust
run: |
curl -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal --target wasm32-unknown-unknown
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"
- name: Actual WASM contract
run: nice -n 19 python3 tools/airdef.py test-wasm
+1 -1
View File
@@ -1,7 +1,7 @@
/horizon/
run-home/
.horizon-cache/
airdef-mod/target/
airdef-core/target/
__pycache__/
/out/
.DS_Store
+3
View File
@@ -0,0 +1,3 @@
[submodule "horizon"]
path = horizon
url = https://gitea.maoniao.team/chexit/horizon-airdef.git
-1
View File
@@ -1 +0,0 @@
b6c936f82b08798057161bdfa577e3aac53fb91e
+93 -25
View File
@@ -1,11 +1,18 @@
# AirDef — дальнобойные дроны и ПВО для Horizon
Мод для Horizon (Minecraft 26.3 на Rust): Шахед-136, Герань-3, Patriot и Гепард с 3D-моделями,
наведением ракет, слежением башен, падением сбитых дронов и эффектами взрывов.
Клиентский sandbox-мод для Horizon (Minecraft 26.3 на Rust): налёты дронов и ракет,
эшелонированная ПВО, раздельные батареи, наземная логистика, разведка, РЭБ, повреждения,
повторы и экспорт видео. Характеристики и временные масштабы игровые; это не тренажёр реальных комплексов.
Работает на **своём форке Horizon** (`horizon/`, ветка `airdef`): в нём добавлен API отрисовки
Работает на **[своём форке Horizon](https://gitea.maoniao.team/chexit/horizon-airdef)**
(`horizon/` — сабмодуль, закреплённый SHA): в нём добавлен API отрисовки
3D-моделей, которого нет в основном Horizon.
Рабочая ветка — **`kimi-work`**. Подробный проверенный объём и оставшаяся приёмка:
[состояние задач](docs/IMPLEMENTATION-STATUS.md). Для передачи разработки:
[технический журнал и handoff](docs/CODEX-HANDOFF.md). Открытый issue не означает отсутствие
реализации: по просьбе владельца агенты оставляют комментарии, но не закрывают задачи.
![Перехваты](screenshots/intercepts.jpg)
## Запуск
@@ -16,10 +23,21 @@
Коротко, из исходников:
```bash
python3 tools/airdef.py all # скачать Horizon, наложить патчи форка, собрать игру и мод, установить мод
git switch kimi-work
git pull --ff-only
git submodule update --init --recursive # также выполняется командой all
python3 tools/airdef.py all # получить закреплённый движок, собрать игру и мод, установить мод
python3 tools/airdef.py play # запустить (аргументы игры — после: --world "Имя мира")
```
`all` синхронизирует URL сабмодуля из `.gitmodules`, включая обновление со старого upstream.
Продолжение 4 ноября: [модели, границы ядра, общий каталог, API29 и массовая акустика](docs/CONTINUATION-2026-11-04.md).
Диагностика в игре: `/airdef capabilities` показывает доступность API, принятие запроса и
подготовку дыма, акустики и захвата именно этого мода. Подготовка не означает готовый GPU-кадр или MP4.
Для разработчика: `python3 tools/airdef.py test-wasm` — лёгкий ABI-тест;
`python3 tools/airdef.py test-budgets` — отдельный тяжёлый сценарий с JSON-отчётом.
Для разработки: `./install.sh` перегенерирует модели (`tools/gen_models.py`, нужен Pillow) и звуки
(`tools/gen_sounds.py`, нужны numpy и ffmpeg), собирает и ставит мод. Сгенерированные файлы лежат в репозитории,
так что для обычной сборки нужен только Rust.
@@ -52,10 +70,10 @@ CI: `.gitea/workflows/build.yml` на каждый пуш собирает то
волнами по типам), дальность старта, цели и **ПУСК**. Цели:
- *только объекты* — всё летит по отмеченным объектам (или по игроку, если их нет);
- *объекты и ПВО* — треть ударных средств бьёт по случайным комплексам;
- *умный противник* — планировщик знает, где стоят комплексы и что видят их РЛС: ведёт дроны и крылатые ракеты
- *умный противник* — планировщик использует наблюдённые контакты и последние известные позиции комплексов: ведёт дроны и крылатые ракеты
маршрутами в обход зон поражения, низко, за рельефом и через мёртвые зоны; «Герберы» прилетают на 15 с раньше,
чтобы оттянуть ракеты; «Ланцеты» идут по Гепардам и Панцирям, Х-22/Циркон и часть баллистики — по дальнобойным
комплексам; на каждую РЛС дальнего обнаружения идут 2–3 быстрых ударника (Х-22, Циркон, Искандер, Кинжал, затем Х-101,
комплексам; на наблюдённые РЛС дальнего обнаружения выделяются 2–3 быстрых ударника (Х-22, Циркон, Искандер, Кинжал, затем Х-101,
Герань-3, Ланцет, Шахед; не больше четверти налёта); всё остальное стартует со сдвигом так, чтобы прилететь одновременно.
После налёта приходит отчёт: сколько сбито и прорвалось, ракет ПВО потрачено, комплексов потеряно, урон объектам.
@@ -72,16 +90,39 @@ CI: `.gitea/workflows/build.yml` на каждый пуш собирает то
**Сохранение.** Комплексы, объекты, их повреждения и настройки сохраняются отдельно для каждого мира (и для каждого
сервера); уничтоженный комплекс остаётся остовом и после перезахода, пока его не отремонтируют.
Налёт в воздухе тоже сохраняется: дроны, очередь их запуска и незавершённые задания на маршрут
восстанавливаются, и перезаход не обрывает перенацеливание. Ракеты-перехватчики в воздухе и площадки
запуска не сохраняются; сценарий — стартовое состояние и налёт не несёт.
**Сеть ПВО.** Каждая единица делится целями со всеми в радиусе 2,25 км (линия связи): РЛС дальнего обнаружения
даёт раннее предупреждение всем, пусковая без своей РЛС (P1-SUN) стреляет по чужим данным. Пушкам (Гепард,
**Сеть ПВО.** Единицы обмениваются измеренными треками в пределах игровой связи; повреждение связи
сокращает её дальность. Можно поставить несколько С-400/С-500 без собственной РЛС и общие радары
поиска, сопровождения и мачтового обзора: N → «Разместить элементы батареи…».
Поисковый радар даёт подсказку; огневой должен сам измерить цель, прежде чем разрешить пуск.
Старая сборная конфигурация сохранена. [Команды, источники и ограничения](docs/BATTERIES-AND-COLD-LAUNCH.md).
P1-SUN также использует чужие данные. Пушкам (Гепард,
пушки Панциря) нужна своя цель: они стреляют только по тому, что видят сами. Уничтоженная РЛС — дыра в сети.
**Радиомолчание.** `/airdef radar <номер> off|on` или кнопка в карточке техники на карте
выключает/включает собственный радар. Приём разрешённых внешних треков сохраняется; чужой трек
не заменяет обязательное собственное сопровождение. Выключение не стирает старые сведения противника:
он продолжает использовать последнюю наблюдённую позицию, а пуски и РЭБ могут снова раскрыть технику.
**Логистика.** Пока нет ни одного склада, магазины пополняются сами, как раньше. Как только поставлен склад,
боекомплект считается: комплекс без ракет пишет «ЖДЁТ БК»; в 60 м от склада он перезаряжается прямо с него, а
дальние обслуживают **ТЗМ**: заправляются на складе (2 перезарядки), сами едут к ждущим комплексам, ближайшим
первым, и возвращаются. Запас склада — 30 перезарядок, он виден в сводке. Склад и ТЗМ детонируют всем грузом.
Ударная **RM48U у С-400** — отдельный условный игровой боеприпас, который делит четыре ячейки
с ракетами ПВО. `/airdef ground-stock <склад> <количество>` задаёт конечный начальный запас
sandbox-сценария, `/airdef ground-load <С-400>` загружает одну ракету рядом со складом либо
создаёт заявку на доставку ТЗМ. Груз едет физически; снятая ракета ПВО возвращается на склад.
Заявка и груз сохраняются в пути. `/airdef ground-unload <С-400>` выгружает ракету у склада,
а вдали создаёт заявку на обратный вывоз ТЗМ. Одна ракета резервируется от пуска до забора;
`/airdef ground-cancel <С-400>` отменяет ещё ожидающую доставку или вывоз.
После забора ракета находится в машине и едет на склад. Отмена заявки не возвращает уже вывезенный груз в ПУ.
Без склада этот ударный боеприпас сам не появляется. Бук и остальные комплексы такого профиля пока не имеют.
Порядок подготовки, разведка и номера двух списков: [как ударить по ПУ](docs/GROUND-STRIKES.md).
**Перемещение.** **Пульт перемещения**: навестись на технику (выбрать), затем на точку на земле — она
сворачивается (С-400 и другие с вертикальным пуском дольше, Гепард и Панцирь быстро), едет по рельефу и
разворачивается; всё это время не стреляет и не светит РЛС. Или `/airdef move <номер>` — к тому месту, где ты стоишь.
@@ -95,9 +136,12 @@ CI: `.gitea/workflows/build.yml` на каждый пуш собирает то
**Умный противник учится.** Он запоминает, откуда его налёты сбивали, а откуда они прорывались, и следующий
налёт ведёт с лучшего направления; помнит комплексы, выдавшие себя пуском, и станции РЭБ, и во время налёта
перенацеливает ещё не взлетевшие Ланцеты и Шахеды на них; если цель-комплекс уничтожен, дроны идут к
следующему известному. Дроны под обстрелом прижимаются к земле.
следующему известному. Маршруты к новым целям достраиваются по бюджету планировщика в следующих тиках:
необработанное задание не теряется, старый безопасный участок остаётся до готовности нового, а дрон без
маршрута летит прямо только до ближайшего бюджета. Дроны под обстрелом прижимаются к земле.
**Ночь.** Ночью пушки попадают втрое хуже, если цель не освещена. Освещают **прожекторы** (луч ведёт ближайшую
**Ночь.** Исправные пушки с собственным свежим радарным сопровождением не теряют точность из-за темноты.
Цели освещают **прожекторы** (луч ведёт ближайшую
цель из сети, приоритет — цели пушек) и **осветительные ракеты**: пушечные комплексы пускают их сами (раз в
25 с на цель в темноте), игрок — **осветительным пистолетом** или `/airdef flare`. Ракета висит ~30 с и
освещает всё вокруг на ~60–90 м.
@@ -110,6 +154,10 @@ CI: `.gitea/workflows/build.yml` на каждый пуш собирает то
тонмаппинг (ванильный диапазон не трогается, сжимается только то, что ярче). Источники передаются движку новым
API мода `render.set-lights` (до 512, плавно интерполируются), режим — `render.set-lighting`.
В HD дымовые следы ракет немного уплотнены; число сегментов и время появления/выгорания сохранены.
Это относится к ракетам ПВО, RM48U, крылатым, сверхзвуковым и баллистическим средствам;
дым пожаров и слабая дымка винтовых дронов остались прежними.
**Сетка J** после сбития ещё 3,5 с держит камеру на сбитой цели, и комплекс в это время не пропадает из сетки.
**Повреждения.** Взрыв рядом с комплексом повреждает его: он хуже поворачивается, хуже видит и попадает,
@@ -118,6 +166,11 @@ API мода `render.set-lights` (до 512, плавно интерполиру
пострадать. Объекты (Целеуказатель или `/airdef target here`) имеют прочность, она видна в сводке. Ремонт —
кнопкой в меню или `/airdef repair`.
Известные стены и рельеф ослабляют **непрямой** урон корпусу, узлам и объектам; проёмы дают
частичное воздействие. Используется геометрия, известная перед разрушением. При неизвестной или
устаревшей геометрии сохраняется прежний урон без защиты; поздний ответ его повторно не наносит.
Прямое вооружённое попадание этим ослаблением не отменяется.
**Монитор комплекса:** клавиша **K** листает комплексы по очереди, после последнего монитор скрывается. Слева вверху показано:
- состояние комплекса (поиск, сопровождение, доворот, захват, пуск, огонь, перезарядка, огонь запрещён);
- его РЛС: цели, по которым он работает, красным, остальные серым, текущая цель жёлтым;
@@ -157,12 +210,10 @@ API мода `render.set-lights` (до 512, плавно интерполиру
- `/airdef import` — перенести в текущий мир комплексы и цели из старой версии мода (до 0.2.x они были общими для всех миров);
- `/airdef raid` — налёт, настроенный в меню; `/airdef target here` — отметить объект под ногами; `/airdef repair` — ремонт;
- `/airdef lastchance <on|off>` — «последний шанс»: комплекс стреляет и по классу вне ролей, если цель вот-вот попадёт (по умолчанию вкл; сохраняется);
- `/airdef sites` — известные пусковые площадки (ПУ) и ударные ракеты; `/airdef strike <номер ПУ>` — ответный удар по ПУ (#101, «удары по ПУ»). Как это играется:
- **Разведка без волшебства.** Площадку находит только работающая РЛС: либо пуск в её досягаемости (низкая цель: радиогоризонт и холмы решают) даёт точечное наблюдение, либо собственный трек вылетевшей цели «указывает назад» лучом в пару градусов, а время полёта с момента пуска (тревоги) на скорости цели даёт дальность (±8% и секунда времени пуска); у баллистической ракеты дуга точнее. Две РЛС, держащие одну цель, дают два наблюдения. Наблюдения сводятся методом наименьших квадратов, ответ всегда с кругом ошибки (90%), он сужается с каждым пуском. Если места не получилось (круг шире 800 блоков или есть только лучи вдоль одной линии), известен только **азимут** (на скопе метка «N?» на краю), удар невозможен. С местом: ромб на скопе (круг ошибки пунктиром) или метка на краю; в панели строка «Известных ПУ…». Далёкие площадки (километры) открываются грубо (сотни блоков) и бить их почти бесполезно, пока не накопятся пуски.
- **Удар.** Ударных ракет мало (3 в запасе, максимум 4, новая за 5 минут), дальность до 4500 блоков; стартуют оттуда, где вы стоите, летят 4 блока в тик (2 км за 25 с) в точку *оценки*. На подлёте ракету может сбить ПВО противника: у ПУ её нет (40%), лёгкая (35%, сбивает в 30%) или тяжёлая (25%, 65%), у баллистических батарей тяжёлая чаще; узнаёте только по итогу. Разброс ракеты 14 блоков; решает истинное расстояние до ПУ: до 35 блоков — **уничтожена** (запас сгорел и рвётся, отложенные запуски отменены, огонь и дымящийся остов, взрыв общим кодом), до 90 — **подавлена** на 30 с (пуски отложены, не отменены), дальше — **промах**, воронка рядом, ПУ цела: очередь за попадание в соседний грунт не списывается. Плохо известную ПУ (круг в сотни блоков) бить почти бесполезно.
- **Вне карты.** ПУ без земли (нет загруженной карты) тоже находится: азимут и дальность по трекам, но не рисуется. Удар, который попал бы, прекращает её пуски («результат не виден»); промах теряется.
- **Цена выбора.** Ракета запаса не вернётся, пока летит, налёт идёт: близкие площадки не остановить, далёкие (крылатые и баллистические за 2–4 км) успеваете, но для этого нужны РЛС с обзором в сторону налёта и риск промаха или ПВО противника. Отчёт налёта называет сорванные пуски: «Налёт сорван ударами по ПУ (№…): не взлетело N из заявленных M».
- Запись: удар попадает в журнал повтора (строка и взрыв/огонь на карте), сами ПУ в повторе не рисуются. Запас ракет входит в сохранение и сценарий (`strikes <запас> <тиков до следующей>`). Все числа механики в одной таблице `TUNE` в `src/sim/strike.rs`.
- `/airdef sites` — известные пусковые площадки (ПУ). РЛС с прямой видимостью может заметить сам пуск и получить неточную позицию; несколько наблюдённых пусков уточняют её. Обнаруженный позже дрон даёт только слабое предположение об обратном курсе: скрытые координаты площадки и время невидимого старта не используются. Повторные треки одного полёта не создают ложную точность.
- `/airdef strike <номер ПУ>` — ручной удар по разведанной площадке из готового физического С-400 с отдельно загруженной RM48U (игровой профиль, #118). Четыре ячейки делятся с боезапасом ПВО; приказ резервирует носитель и ячейку, открывает крышку и списывает одну ударную ракету при выбросе. Выбирается готовый комплекс с наибольшим остатком RM48U, затем ближайший к цели. Есть открытие ТПК, выброс, отложенное включение двигателя и разгон, ограниченная игровая траектория, столкновения и запись пуска. Несуществующее «ПВО площадки» не перехватывает ракету по броску вероятности.
- `/airdef ground-stock <номер склада> <количество>` — задать остаток RM48U для sandbox-сценария (по умолчанию 0). `/airdef ground-load <номер С-400>` загружает одну ракету у склада либо заказывает ТЗМ; `ground-unload` возвращает её у склада либо заказывает вывоз; `ground-cancel` отменяет ожидающую заявку. Доставка и обратный вывоз через ТЗМ реализованы, запас и груз сохраняются. [Пошаговый пример](docs/GROUND-STRIKES.md). Совместимость профиля основана на [публикации ГУР](https://gur.gov.ua/content/warsanctions-hur-mo-rozkryvaie-budovu-komponentnu-bazu-ta-pidpryiemstva-kooperatsii-z-vyrobnytstva-udarnykh-raket-rm48u.html); это сообщение ведомства, не независимая сертификация. Дальность, форма полёта и оформление условны для Minecraft.
- `/airdef deploy s400_launcher` и `s500_launcher` — отдельные пусковые без своей РЛС; `radar_search`, `radar_track`, `radar_height` — обзорная, сопровождающая и мачтовая игровые РЛС. Они также доступны через меню N → «Разместить элементы батареи…». `/airdef battery` показывает состав и связь; `/airdef battery <номер> integrated|launcher` меняет конфигурацию, `/airdef radar <номер> multi|search|engagement|height` — роль отдельной РЛС. Обзорная РЛС передаёт подсказки; станция сопровождения должна сама получить свежее измерение, чтобы разрешить пуск. Старые С-400/С-500 сохраняют упрощённую сборную конфигурацию. [Устройство игровой батареи и пуска](docs/BATTERIES-AND-COLD-LAUNCH.md).
- `/airdef roles` — показать, по каким классам целей работает каждый комплекс; `/airdef roles <patriot|gepard|pantsir|s400|s500|all> <классы|default>` — задать (классы через запятую: `drone`, `jet`, `cruise`, `supersonic`, `ballistic` или `all`), например `/airdef roles s400 cruise,ballistic`;
- `/airdef doctrine` — доктрины комплексов (#47; в меню N: «Доктрины…»): `/airdef doctrine <номер|all> reserve <K>` — держать K ракет для срочных целей (баллистика или до удара меньше 12 с); `salvo eco|normal|heavy` — сколько перехватчиков на цель (только базовые / как обычно / на один больше); `sector <центр°> <полуширина°>` или `sector off` — сектор ответственности (0° — север); `guard <объект№>[,<№>]` или `guard off` — стрелять только по тому, что идёт на охраняемые объекты (отметка: `/airdef target here`). По умолчанию ограничений нет; последний шанс сильнее доктрины; `/airdef why <номер>` называет, какая настройка остановила или разрешила пуск; сохраняется с миром и сценариями. Карта охраны и пробелов в ней — вместе с картой (#48).
- `/airdef deploy <patriot|gepard|pantsir|s400|s500>` — поставить комплекс в 8 блоках перед собой;
@@ -205,7 +256,7 @@ API мода `render.set-lights` (до 512, плавно интерполиру
| Гепард | 2 × 35 мм, башня и стволы со слежением и упреждением, 160 очередей | 135 (слежение с 195) |
| Панцирь-С1 | 12 × 57Э6 и 2 × 30 мм; модуль поворачивается, пакеты и стволы поднимаются | ракеты 25–225, пушки 90 |
| С-400 | 4 × 48Н6, вертикальный холодный старт, РЛС обзора на прицепе | 30–720 |
| С-500 | 4 × 77Н6, холодный старт, самые быстрые ракеты | 40–1050 |
| С-500 | 2 × 77Н6, холодный старт, самые быстрые ракеты | 40–1050 |
| IRIS-T SLM | 8 ракет, вертикальный пуск, быстрые и манёвренные | 15–600 |
| NASAMS | 6 × AMRAAM, наводимая пусковая на прицепе | 10–450 |
| Бук-М2 | 4 × 9М317 на направляющих, башня с РЛС подсвета | 20–675 |
@@ -219,7 +270,16 @@ API мода `render.set-lights` (до 512, плавно интерполиру
**Согласование огня.** Комплексы делят цели между собой: на обычную цель идёт одна ракета, на баллистическую две; чем ближе цель к своей точке попадания,
тем больше перехватчиков разрешено на неё сразу (за ~12 с до удара ещё один, за ~5 с — ещё один). Комплекс, у которого кончились ракеты
или идёт перезарядка, цель не держит; тот, кто не смог навестись за ~2 с, отпускает её другим. Пушки расходятся по разным целям. Первыми бьют по самым опасным (быстрым и тяжёлым) целям, при этом ложные
«Герберы» выглядят для них как настоящие. Шанс поражения падает, если цель быстрее перехватчика.
«Герберы» выглядят для них как настоящие. Геометрия встречи проверяется по движению обоих объектов
за тик, а остаточный шанс учитывает фактическую скорость перехватчика.
**Энергетика перехватчика.** Сначала ракета выходит из ТПК без двигателя: у С-400 это 1,0 с,
у С-500 — 1,2 с; только потом в её текущей точке зажигается факел, и тяга плавно нарастает.
После выброса ракета разгоняется, но двигатель работает конечное игровое время. После выгорания
ракета летит по инерции, теряет скорость и манёвренность; при недостаточной скорости сопровождение
срывается. Факел, звук двигателя и новый дым прекращаются при выгорании и в live, и в повторе;
уже созданный дым продолжает рассеиваться. У ракет с горячим (рельсовым) пуском тяга тоже
нарастает плавно, но холодного выброса нет; электрический P1-SUN не получает ракетную струю.
**Последний шанс** (`/airdef lastchance on|off`, по умолчанию вкл). Комплекс стреляет и по классу целей вне своих ролей
(С-400, С-500 и Patriot по умолчанию не бьют дроны), если цель долетит до своей точки меньше чем за 10 с и на ней ещё нет
@@ -270,16 +330,18 @@ API мода `render.set-lights` (до 512, плавно интерполиру
## Устройство
```
HORIZON_COMMIT коммит апстрима Horizon, на который накладываются патчи
horizon-patches/ изменения форка (git format-patch); tools/airdef.py fork собирает из них horizon/
horizon/ форк (не в репозитории; ветка airdef). Что в нём меняется:
.gitmodules URL отдельного репозитория движка
horizon/ git submodule: точный SHA форка Horizon. Что в нём меняется:
crates/horizon-mod-sdk/wit/horizon.wit render.set-models, spawn-particles, play-sound,
query-ground / ground
crates/horizon-mods/src/runtime.rs хост этих функций
crates/horizon-client/src/game/mod_models.rs интерполяция и отрисовка моделей, частицы
crates/horizon-client/src/gfx/mod_post.rs пост-проход мода: render.set-post / set-params
airdef-mod/ сам мод: Rust → WebAssembly
src/sim.rs симуляция: дроны, ракеты, ПВО, эффекты (20 тиков/с)
airdef-core/ SDK-free сборка общего ядра; использует те же исходники sim, без копии
airdef-mod/ адаптер: Rust → WebAssembly
src/sim/mod.rs симуляция: дроны, ракеты, ПВО, эффекты (20 тиков/с)
src/sim/battery.rs конфигурации пусковых и роли общей РЛС
src/sim/launch.rs резервирование ячеек и анимация крышек ТПК
src/lib.rs предметы, команды, сохранение, передача в движок
src/panel.rs сводка, src/radar.rs — радар, src/monitor.rs — монитор комплекса
assets/airdef/sounds звуки (генерирует tools/gen_sounds.py)
@@ -299,11 +361,17 @@ run-home/ тестовая игровая папка (для пров
Модели — обычные блочные JSON-модели, по одной на часть: корпус, винт, башня, стволы. Их генерирует
`tools/gen_models.py`. Координаты элементов должны быть в пределах −16..32, иначе Horizon отбросит модель.
Рельеф мод узнаёт через `render.query-ground`: присылает колонки, а движок отвечает высотой по карте
высот на следующем тике.
Рельеф и коллизии приходят асинхронно через ground/ray/section queries. Высотной карты недостаточно
для точного попадания: известные блоки и формы проверяются отдельно; ожидание/Unknown не считается
доказанным свободным путём. Историческое отображение повтора отделено от live-геометрии симуляции.
## Известные ограничения
- Для [#122](https://gitea.maoniao.team/chexit/airdef/issues/122) воспроизведено и исправлено исчерпание fuel при массовых взрывах:
каждый взрыв больше не обходит всю карту высот. Проверка на конкретном Windows-компьютере ещё нужна;
прирост FPS этим исправлением не обещается.
- Мод клиентский: дроны и ПВО видит только тот, у кого он стоит. Мультиплеер не поддерживается.
- Окно Horizon на macOS не рисует кадры, пока оно перекрыто другими окнами (это поведение движка).
- Шейдер работает, только если не включён шейдер-пак Horizon (они взаимоисключающие).
Разработка и обновление закреплённого движка: [docs/ENGINE.md](docs/ENGINE.md).
+16
View File
@@ -0,0 +1,16 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "airdef-core"
version = "0.2.0"
dependencies = [
"glam",
]
[[package]]
name = "glam"
version = "0.30.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19fc433e8437a212d1b6f1e68c7824af3aed907da60afa994e7f542d18d12aa9"
+13
View File
@@ -0,0 +1,13 @@
[package]
name = "airdef-core"
version = "0.2.0"
edition = "2024"
publish = false
[dependencies]
glam = "0.30"
[features]
test-fixtures = []
[workspace]
+13
View File
@@ -0,0 +1,13 @@
# AirDef headless simulation
This package compiles the same `airdef-mod/src/sim` source as the game adapter, with `glam` as its only dependency. A checkout does not need the Horizon submodule to build or run it:
```sh
cargo test --manifest-path airdef-core/Cargo.toml
cargo run --manifest-path airdef-core/Cargo.toml --release --example sim_run -- --list
cargo run --manifest-path airdef-core/Cargo.toml --release --example sim_run -- --scenario big-smart
```
The shared scenario harness runs for both packages. Adapter integration tests for layout and smoke stay in `airdef-mod`; `core_boundary` verifies the public type facade and deterministic combat trace.
This is an incremental boundary: the simulation still produces rendering and audio declarations and formats some UI text. Moving those outputs and diagnostics to adapters, remain follow-up work. The mod re-exports `airdef_core::sim` as its existing public facade.
+8
View File
@@ -0,0 +1,8 @@
//! The enemy-picture bench (#127) without building the Horizon SDK.
extern crate airdef_core as airdef;
#[path = "../../airdef-mod/examples/intel_bench.rs"]
mod bench;
fn main() {
bench::main();
}
+8
View File
@@ -0,0 +1,8 @@
//! Run the same native scenario CLI without building the Horizon SDK.
extern crate airdef_core as airdef;
#[path = "../../airdef-mod/examples/sim_run/main.rs"]
mod runner;
fn main() {
runner::main();
}
+6
View File
@@ -0,0 +1,6 @@
//! SDK-independent build of the same simulation used by the AirDef adapter.
//!
//! The source remains shared while the domain/presentation boundary is extracted;
//! no generated copy can drift from the mod's simulation.
#[path = "../../airdef-mod/src/sim/mod.rs"]
pub mod sim;
+166
View File
@@ -0,0 +1,166 @@
//! The mod's headless scenarios run against the SDK-independent package too.
extern crate airdef_core as airdef;
#[path = "../../airdef-mod/examples/sim_run/harness.rs"]
mod harness;
fn check(sc: harness::Scenario) -> harness::Report {
let r = harness::run(&sc);
let problems = r.problems();
assert!(problems.is_empty(), "scenario {} failed: {problems:?}\n{}", r.name, r.text());
assert!(r.launched > 0);
r
}
#[test]
fn big_smart_raid_on_61_systems() {
let r = check(harness::big_smart());
assert_eq!(r.units, 61);
assert!(r.fired > 0 && r.ground_queries > 0);
}
#[test]
fn logistics_trucks_depot_and_raid() {
let r = check(harness::logistics());
assert!(r.truck_busy_ticks > 0 && r.fired > 0);
}
#[test]
fn ew_and_adaptive_enemy_over_three_raids() {
assert_eq!(check(harness::ew_adaptive()).raids_ended, 3);
}
#[test]
fn same_seed_same_result() {
let a = harness::run(&harness::logistics());
let b = harness::run(&harness::logistics());
assert_eq!((a.ticks_run, a.launched, a.kills, a.hits, a.fired, a.ground_queries), (b.ticks_run, b.launched, b.kills, b.hits, b.fired, b.ground_queries));
}
#[test]
fn overlapping_mass_strikes_on_flat_world() {
use airdef::sim::{Aim, Approach, DroneKind as D, Ground, Out, RaidOrder, Sam, Sim};
use glam::DVec3;
let sc = harness::big_smart();
let terrain = harness::Terrain::Flat(70);
let mut sim = Sim::new(sc.seed);
sim.damage = false;
for unit in &sc.units {
let id = sim.id();
sim.sams.push(Sam::new(id, unit.kind, DVec3::new(unit.pos.x, 70.0, unit.pos.z), unit.heading));
}
sim.targets = vec![DVec3::new(0.0, 70.0, 0.0)];
sim.target_health = vec![100.0];
// Exact composition of the menu's "Массированный удар" preset.
let order = RaidOrder { kinds: vec![(D::Gerbera, 8), (D::Shahed, 12), (D::Geran3, 4), (D::Kh101, 4), (D::Kalibr, 4), (D::Kh22, 2), (D::Iskander, 2)], approach: Approach::AllSides, aim: Aim::Smart, dist: 4000.0 };
let mut ground = Ground::default();
let mut pending = Vec::new();
let mut out = Out::default();
let targets = sim.targets.clone();
assert_eq!(sim.order_raid(&order, &targets, &mut out), 36);
let mut second = false;
let mut peak = 0;
for now in 1..=12000 {
if !second && !sim.planning() {
assert_eq!(sim.order_raid(&order, &targets, &mut out), 36);
second = true;
}
ground.answer(std::mem::take(&mut pending), now);
out = Out::default();
sim.step(&mut ground, None, &mut out);
let wanted = ground.take_wanted();
pending = wanted.into_iter().map(|(x, z)| (x, z, 70)).collect();
let sections = ground.world.take_wanted(now);
ground.world.serve(&terrain, sections, now);
peak = peak.max(sim.drones.iter().filter(|d| d.alive()).count());
assert!(sim.drones.iter().all(|d| d.pos.is_finite() && d.vel.is_finite()));
if sim.launched >= 72 && peak > 36 { break; }
}
eprintln!("overlapping mass strikes: launched {}, peak airborne {peak}", sim.launched);
assert!(second && sim.launched >= 72, "second raid failed to launch; launched {}", sim.launched);
assert!(peak > 36, "raids never overlapped; peak {peak}");
}
#[test]
fn overlapping_oreshnik_splits_are_recorded() {
use airdef::sim::{Aim, Approach, DroneKind, Ground, Out, RaidOrder, Sim};
use glam::DVec3;
let mut sim = Sim::new(1);
sim.damage = false;
let targets = vec![DVec3::new(0.0, 70.0, 0.0)];
sim.targets = targets.clone();
sim.target_health = vec![100.0];
let order = RaidOrder { kinds: vec![(DroneKind::Oreshnik, 40)], approach: Approach::Sector, aim: Aim::Objects, dist: 2600.0 };
let terrain = harness::Terrain::Flat(70);
let mut ground = Ground::default();
let mut pending = Vec::new();
let mut out = Out::default();
assert_eq!(sim.order_raid(&order, &targets, &mut out), 40);
let mut second = false;
let mut peak = 0;
let mut peak_subs = 0;
for now in 1..=10000 {
if !second && !sim.planning() {
assert_eq!(sim.order_raid(&order, &targets, &mut out), 40);
second = true;
}
ground.answer(std::mem::take(&mut pending), now);
out = Out::default();
sim.step(&mut ground, None, &mut out);
pending = ground.take_wanted().into_iter().map(|(x, z)| (x, z, 70)).collect();
let sections = ground.world.take_wanted(now);
ground.world.serve(&terrain, sections, now);
peak = peak.max(sim.drones.iter().filter(|d| d.alive()).count());
peak_subs = peak_subs.max(sim.drones.iter().filter(|d| d.alive() && d.kind == DroneKind::OreshnikSub).count());
assert!(sim.drones.iter().all(|d| d.pos.is_finite() && d.vel.is_finite()));
if second && sim.launched >= 80 && !sim.replays.is_empty() { break; }
}
eprintln!("overlapping oreshnik: launched {}, peak airborne {peak}, peak submunitions {peak_subs}, replays {}", sim.launched, sim.replays.len());
assert_eq!(sim.launched, 2880);
assert!(peak_subs > 36, "expected many simultaneous submunitions");
assert!(!sim.replays.is_empty(), "recording did not finish");
}
#[test]
fn two_maximum_menu_raids_with_answered_flat_terrain() {
use airdef::sim::{Aim, Approach, Ground, Out, RaidOrder, Sam, Sim, catalog::RAID_KINDS};
use glam::DVec3;
let sc = harness::big_smart();
let terrain = harness::Terrain::Flat(70);
let mut sim = Sim::new(sc.seed);
for unit in &sc.units {
let id = sim.id();
sim.sams.push(Sam::new(id, unit.kind, DVec3::new(unit.pos.x, 70.0, unit.pos.z), unit.heading));
}
let targets = vec![DVec3::new(0.0, 70.0, 0.0)];
sim.targets = targets.clone();
sim.target_health = vec![100.0];
// The maximum selectable by the menu: 40 for each raid kind.
let order = RaidOrder { kinds: RAID_KINDS.iter().copied().map(|kind| (kind, 40)).collect(), approach: Approach::AllSides, aim: Aim::Smart, dist: 300.0 };
let expected = RAID_KINDS.len() as u32 * 40;
let mut ground = Ground::default();
let mut pending = Vec::new();
let mut out = Out::default();
assert_eq!(sim.order_raid(&order, &targets, &mut out), expected);
let mut second = false;
let mut overlap = false;
let mut peak = 0;
for now in 1..=5000 {
if !second && !sim.planning() {
overlap = !sim.queue.is_empty() || sim.drones.iter().any(|d| d.alive());
assert_eq!(sim.order_raid(&order, &targets, &mut out), expected);
second = true;
}
ground.answer(std::mem::take(&mut pending), now);
out = Out::default();
sim.step(&mut ground, None, &mut out);
pending = ground.take_wanted().into_iter().map(|(x, z)| (x, z, 70)).collect();
let sections = ground.world.take_wanted(now);
ground.world.serve(&terrain, sections, now);
peak = peak.max(sim.drones.iter().filter(|d| d.alive()).count());
assert!(sim.drones.iter().all(|d| d.pos.is_finite() && d.vel.is_finite()));
if second && sim.launched >= expected * 2 && !sim.replays.is_empty() { break; }
}
eprintln!("max menu raids: requested {}, launched {}, peak {peak}, replays {}", expected * 2, sim.launched, sim.replays.len());
assert!(second && overlap && sim.launched >= expected * 2 && peak > 40);
assert!(!sim.replays.is_empty(), "raid recording did not finish");
}
+8
View File
@@ -6,10 +6,18 @@ version = 4
name = "airdef"
version = "0.2.0"
dependencies = [
"airdef-core",
"glam",
"horizon-mod-sdk",
]
[[package]]
name = "airdef-core"
version = "0.2.0"
dependencies = [
"glam",
]
[[package]]
name = "anyhow"
version = "1.0.104"
+4
View File
@@ -9,9 +9,13 @@ description = "AirDef: long-range drones and air defence for the AirDef fork of
crate-type = ["cdylib", "rlib"]
[dependencies]
airdef-core = { path = "../airdef-core" }
horizon-mod-sdk = { path = "../horizon/crates/horizon-mod-sdk" }
glam = "0.30"
[dev-dependencies]
airdef-core = { path = "../airdef-core", features = ["test-fixtures"] }
[profile.release]
opt-level = "s"
lto = true
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "airdef:block/radar_mast"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "airdef:block/radar_mast_burnt"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "airdef:block/rm48u"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "airdef:block/tpk_cap"
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "airdef:block/tpk_cap_burnt"
}
}
}
+5
View File
@@ -30,10 +30,13 @@
"block.airdef.s400_tubes": "ТПК 48Н6",
"block.airdef.s500_chassis": "Шасси С-500",
"block.airdef.s500_tubes": "ТПК 77Н6",
"block.airdef.tpk_cap": "Крышка ТПК (анимация)",
"block.airdef.radar_mast": "Радиомачта (секция высоты)",
"block.airdef.radar_trailer": "Прицеп РЛС",
"block.airdef.radar_panel": "РЛС обзора",
"block.airdef.m57e6": "57Э6",
"block.airdef.m48n6": "48Н6",
"block.airdef.rm48u": "RM48U (игровой профиль)",
"block.airdef.m77n6": "77Н6",
"block.airdef.kalibr": "Калибр",
"block.airdef.kh22": "Х-22",
@@ -76,6 +79,8 @@
"block.airdef.s400_tubes_burnt": "ТПК 48Н6 (остов)",
"block.airdef.s500_chassis_burnt": "Шасси С-500 (остов)",
"block.airdef.s500_tubes_burnt": "ТПК 77Н6 (остов)",
"block.airdef.tpk_cap_burnt": "Крышка ТПК (анимация) (остов)",
"block.airdef.radar_mast_burnt": "Радиомачта (секция высоты) (остов)",
"block.airdef.irist_chassis_burnt": "Шасси IRIS-T SLM (остов)",
"block.airdef.irist_tubes_burnt": "Пакет IRIS-T (остов)",
"block.airdef.nasams_trailer_burnt": "Прицеп NASAMS (остов)",
+5
View File
@@ -30,10 +30,13 @@
"block.airdef.s400_tubes": "ТПК 48Н6",
"block.airdef.s500_chassis": "Шасси С-500",
"block.airdef.s500_tubes": "ТПК 77Н6",
"block.airdef.tpk_cap": "Крышка ТПК (анимация)",
"block.airdef.radar_mast": "Радиомачта (секция высоты)",
"block.airdef.radar_trailer": "Прицеп РЛС",
"block.airdef.radar_panel": "РЛС обзора",
"block.airdef.m57e6": "57Э6",
"block.airdef.m48n6": "48Н6",
"block.airdef.rm48u": "RM48U (игровой профиль)",
"block.airdef.m77n6": "77Н6",
"block.airdef.kalibr": "Калибр",
"block.airdef.kh22": "Х-22",
@@ -76,6 +79,8 @@
"block.airdef.s400_tubes_burnt": "ТПК 48Н6 (остов)",
"block.airdef.s500_chassis_burnt": "Шасси С-500 (остов)",
"block.airdef.s500_tubes_burnt": "ТПК 77Н6 (остов)",
"block.airdef.tpk_cap_burnt": "Крышка ТПК (анимация) (остов)",
"block.airdef.radar_mast_burnt": "Радиомачта (секция высоты) (остов)",
"block.airdef.irist_chassis_burnt": "Шасси IRIS-T SLM (остов)",
"block.airdef.irist_tubes_burnt": "Пакет IRIS-T (остов)",
"block.airdef.nasams_trailer_burnt": "Прицеп NASAMS (остов)",
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -4,8 +4,7 @@
"missile_ru": "airdef:block/missile_ru",
"booster": "airdef:block/booster",
"dark_metal": "airdef:block/dark_metal",
"ru_green_s31": "airdef:block/ru_green_s31",
"ru_green": "airdef:block/ru_green",
"pilot_olive": "airdef:block/pilot_olive",
"particle": "airdef:block/missile_ru"
},
"elements": [
@@ -844,7 +843,7 @@
16,
2.0
],
"texture": "#ru_green_s31"
"texture": "#pilot_olive"
},
"south": {
"uv": [
@@ -853,7 +852,7 @@
16,
2.0
],
"texture": "#ru_green_s31"
"texture": "#pilot_olive"
},
"east": {
"uv": [
@@ -862,7 +861,7 @@
16,
2.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"west": {
"uv": [
@@ -871,7 +870,7 @@
16,
2.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"up": {
"uv": [
@@ -880,7 +879,7 @@
16,
16
],
"texture": "#ru_green_s31"
"texture": "#pilot_olive"
},
"down": {
"uv": [
@@ -889,9 +888,9 @@
16,
16
],
"texture": "#ru_green_s31"
"texture": "#pilot_olive"
}
}
}
]
}
}
@@ -4,8 +4,7 @@
"missile_ru_b": "airdef:block/missile_ru_b",
"booster_b": "airdef:block/booster_b",
"dark_metal_b": "airdef:block/dark_metal_b",
"ru_green_s31_b": "airdef:block/ru_green_s31_b",
"ru_green_b": "airdef:block/ru_green_b",
"pilot_olive_b": "airdef:block/pilot_olive_b",
"particle": "airdef:block/missile_ru_b"
},
"elements": [
@@ -844,7 +843,7 @@
16,
2.0
],
"texture": "#ru_green_s31_b"
"texture": "#pilot_olive_b"
},
"south": {
"uv": [
@@ -853,7 +852,7 @@
16,
2.0
],
"texture": "#ru_green_s31_b"
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
@@ -862,7 +861,7 @@
16,
2.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
@@ -871,7 +870,7 @@
16,
2.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
@@ -880,7 +879,7 @@
16,
16
],
"texture": "#ru_green_s31_b"
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
@@ -889,9 +888,9 @@
16,
16
],
"texture": "#ru_green_s31_b"
"texture": "#pilot_olive_b"
}
}
}
]
}
}
@@ -1,11 +1,11 @@
{
"ambientocclusion": false,
"textures": {
"ru_green_s21": "airdef:block/ru_green_s21",
"ru_green_s22": "airdef:block/ru_green_s22",
"pilot_olive": "airdef:block/pilot_olive",
"radar_face": "airdef:block/radar_face",
"ru_green": "airdef:block/ru_green",
"particle": "airdef:block/ru_green_s21"
"dark_metal": "airdef:block/dark_metal",
"metal": "airdef:block/metal",
"particle": "airdef:block/pilot_olive"
},
"elements": [
{
@@ -16,7 +16,7 @@
],
"to": [
20.0,
9.0,
7.0,
20.0
],
"faces": {
@@ -25,36 +25,36 @@
0,
0,
16,
9.0
7.0
],
"texture": "#ru_green_s21"
"texture": "#pilot_olive"
},
"south": {
"uv": [
0,
0,
16,
9.0
7.0
],
"texture": "#ru_green_s21"
"texture": "#pilot_olive"
},
"east": {
"uv": [
0,
0,
16,
9.0
7.0
],
"texture": "#ru_green_s21"
"texture": "#pilot_olive"
},
"west": {
"uv": [
0,
0,
16,
9.0
7.0
],
"texture": "#ru_green_s21"
"texture": "#pilot_olive"
},
"up": {
"uv": [
@@ -63,7 +63,7 @@
16,
16
],
"texture": "#ru_green_s22"
"texture": "#pilot_olive"
},
"down": {
"uv": [
@@ -72,7 +72,75 @@
16,
16
],
"texture": "#ru_green_s22"
"texture": "#pilot_olive"
}
}
},
{
"from": [
-2.0,
7.0,
2.0
],
"to": [
18.0,
10.0,
18.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive"
},
"south": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive"
},
"east": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive"
},
"west": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive"
},
"up": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive"
},
"down": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive"
}
}
},
@@ -83,7 +151,7 @@
-10.0
],
"to": [
15.0,
11.0,
14.0,
-4.0
],
@@ -92,7 +160,7 @@
"uv": [
0,
0,
14.0,
10.0,
12.0
],
"texture": "#radar_face"
@@ -101,7 +169,7 @@
"uv": [
0,
0,
14.0,
10.0,
12.0
],
"texture": "#radar_face"
@@ -128,7 +196,7 @@
"uv": [
0,
0,
14.0,
10.0,
6.0
],
"texture": "#radar_face"
@@ -137,7 +205,7 @@
"uv": [
0,
0,
14.0,
10.0,
6.0
],
"texture": "#radar_face"
@@ -146,14 +214,14 @@
},
{
"from": [
-2.0,
9.0,
6.0
0.0,
1.0,
-5.0
],
"to": [
18.0,
11.0,
18.0
16.0,
3.0,
-3.0
],
"faces": {
"north": {
@@ -163,7 +231,7 @@
16,
2.0
],
"texture": "#ru_green"
"texture": "#dark_metal"
},
"south": {
"uv": [
@@ -172,7 +240,75 @@
16,
2.0
],
"texture": "#ru_green"
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
16,
2.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
16,
2.0
],
"texture": "#dark_metal"
}
}
},
{
"from": [
-4.0,
7.0,
4.0
],
"to": [
-2.0,
9.0,
16.0
],
"faces": {
"north": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#metal"
},
"east": {
"uv": [
@@ -181,7 +317,7 @@
12.0,
2.0
],
"texture": "#ru_green"
"texture": "#metal"
},
"west": {
"uv": [
@@ -190,27 +326,95 @@
12.0,
2.0
],
"texture": "#ru_green"
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
16,
2.0,
12.0
],
"texture": "#ru_green"
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
16,
2.0,
12.0
],
"texture": "#ru_green"
"texture": "#metal"
}
}
},
{
"from": [
18.0,
7.0,
4.0
],
"to": [
20.0,
9.0,
16.0
],
"faces": {
"north": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#metal"
},
"east": {
"uv": [
0,
0,
12.0,
2.0
],
"texture": "#metal"
},
"west": {
"uv": [
0,
0,
12.0,
2.0
],
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
2.0,
12.0
],
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
2.0,
12.0
],
"texture": "#metal"
}
}
}
]
}
}
@@ -1,11 +1,11 @@
{
"ambientocclusion": false,
"textures": {
"ru_green_s21_b": "airdef:block/ru_green_s21_b",
"ru_green_s22_b": "airdef:block/ru_green_s22_b",
"pilot_olive_b": "airdef:block/pilot_olive_b",
"radar_face_b": "airdef:block/radar_face_b",
"ru_green_b": "airdef:block/ru_green_b",
"particle": "airdef:block/ru_green_s21_b"
"dark_metal_b": "airdef:block/dark_metal_b",
"metal_b": "airdef:block/metal_b",
"particle": "airdef:block/pilot_olive_b"
},
"elements": [
{
@@ -16,7 +16,7 @@
],
"to": [
20.0,
9.0,
7.0,
20.0
],
"faces": {
@@ -25,36 +25,36 @@
0,
0,
16,
9.0
7.0
],
"texture": "#ru_green_s21_b"
"texture": "#pilot_olive_b"
},
"south": {
"uv": [
0,
0,
16,
9.0
7.0
],
"texture": "#ru_green_s21_b"
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
0,
0,
16,
9.0
7.0
],
"texture": "#ru_green_s21_b"
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
0,
0,
16,
9.0
7.0
],
"texture": "#ru_green_s21_b"
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
@@ -63,7 +63,7 @@
16,
16
],
"texture": "#ru_green_s22_b"
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
@@ -72,7 +72,75 @@
16,
16
],
"texture": "#ru_green_s22_b"
"texture": "#pilot_olive_b"
}
}
},
{
"from": [
-2.0,
7.0,
2.0
],
"to": [
18.0,
10.0,
18.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive_b"
},
"south": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive_b"
}
}
},
@@ -83,7 +151,7 @@
-10.0
],
"to": [
15.0,
11.0,
14.0,
-4.0
],
@@ -92,7 +160,7 @@
"uv": [
0,
0,
14.0,
10.0,
12.0
],
"texture": "#radar_face_b"
@@ -101,7 +169,7 @@
"uv": [
0,
0,
14.0,
10.0,
12.0
],
"texture": "#radar_face_b"
@@ -128,7 +196,7 @@
"uv": [
0,
0,
14.0,
10.0,
6.0
],
"texture": "#radar_face_b"
@@ -137,7 +205,7 @@
"uv": [
0,
0,
14.0,
10.0,
6.0
],
"texture": "#radar_face_b"
@@ -146,14 +214,14 @@
},
{
"from": [
-2.0,
9.0,
6.0
0.0,
1.0,
-5.0
],
"to": [
18.0,
11.0,
18.0
16.0,
3.0,
-3.0
],
"faces": {
"north": {
@@ -163,7 +231,7 @@
16,
2.0
],
"texture": "#ru_green_b"
"texture": "#dark_metal_b"
},
"south": {
"uv": [
@@ -172,7 +240,75 @@
16,
2.0
],
"texture": "#ru_green_b"
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
16,
2.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
16,
2.0
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
-4.0,
7.0,
4.0
],
"to": [
-2.0,
9.0,
16.0
],
"faces": {
"north": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#metal_b"
},
"south": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#metal_b"
},
"east": {
"uv": [
@@ -181,7 +317,7 @@
12.0,
2.0
],
"texture": "#ru_green_b"
"texture": "#metal_b"
},
"west": {
"uv": [
@@ -190,27 +326,95 @@
12.0,
2.0
],
"texture": "#ru_green_b"
"texture": "#metal_b"
},
"up": {
"uv": [
0,
0,
16,
2.0,
12.0
],
"texture": "#ru_green_b"
"texture": "#metal_b"
},
"down": {
"uv": [
0,
0,
16,
2.0,
12.0
],
"texture": "#ru_green_b"
"texture": "#metal_b"
}
}
},
{
"from": [
18.0,
7.0,
4.0
],
"to": [
20.0,
9.0,
16.0
],
"faces": {
"north": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#metal_b"
},
"south": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#metal_b"
},
"east": {
"uv": [
0,
0,
12.0,
2.0
],
"texture": "#metal_b"
},
"west": {
"uv": [
0,
0,
12.0,
2.0
],
"texture": "#metal_b"
},
"up": {
"uv": [
0,
0,
2.0,
12.0
],
"texture": "#metal_b"
},
"down": {
"uv": [
0,
0,
2.0,
12.0
],
"texture": "#metal_b"
}
}
}
]
}
}
+179 -42
View File
@@ -3,6 +3,7 @@
"textures": {
"concrete": "airdef:block/concrete",
"crate": "airdef:block/crate",
"dark_metal": "airdef:block/dark_metal",
"tube_cap": "airdef:block/tube_cap",
"tube": "airdef:block/tube",
"particle": "airdef:block/concrete"
@@ -78,22 +79,22 @@
},
{
"from": [
-12.0,
-13.0,
2.0,
-12.0
-13.0
],
"to": [
0.0,
10.0,
0.0
1.0,
12.0,
1.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
8.0
14.0,
10.0
],
"texture": "#crate"
},
@@ -101,8 +102,8 @@
"uv": [
0,
0,
12.0,
8.0
14.0,
10.0
],
"texture": "#crate"
},
@@ -110,8 +111,8 @@
"uv": [
0,
0,
12.0,
8.0
14.0,
10.0
],
"texture": "#crate"
},
@@ -119,8 +120,8 @@
"uv": [
0,
0,
12.0,
8.0
14.0,
10.0
],
"texture": "#crate"
},
@@ -128,8 +129,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate"
},
@@ -137,8 +138,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate"
}
@@ -146,21 +147,21 @@
},
{
"from": [
-12.0,
-13.0,
2.0,
4.0
3.0
],
"to": [
0.0,
1.0,
10.0,
16.0
17.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate"
@@ -169,7 +170,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate"
@@ -178,7 +179,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate"
@@ -187,7 +188,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate"
@@ -196,8 +197,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate"
},
@@ -205,8 +206,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate"
}
@@ -214,21 +215,21 @@
},
{
"from": [
4.0,
3.0,
2.0,
-12.0
-13.0
],
"to": [
16.0,
17.0,
10.0,
0.0
1.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate"
@@ -237,7 +238,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate"
@@ -246,7 +247,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate"
@@ -255,7 +256,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate"
@@ -264,8 +265,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate"
},
@@ -273,13 +274,149 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate"
}
}
},
{
"from": [
-14.0,
2.0,
27.0
],
"to": [
30.0,
5.0,
29.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
16,
2.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
16,
2.0
],
"texture": "#dark_metal"
}
}
},
{
"from": [
-14.0,
2.0,
-14.0
],
"to": [
-12.0,
5.0,
28.0
],
"faces": {
"north": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
2.0,
16
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
2.0,
16
],
"texture": "#dark_metal"
}
}
},
{
"from": [
6.0,
@@ -485,4 +622,4 @@
}
}
]
}
}
@@ -3,6 +3,7 @@
"textures": {
"concrete_b": "airdef:block/concrete_b",
"crate_b": "airdef:block/crate_b",
"dark_metal_b": "airdef:block/dark_metal_b",
"tube_cap_b": "airdef:block/tube_cap_b",
"tube_b": "airdef:block/tube_b",
"particle": "airdef:block/concrete_b"
@@ -78,22 +79,22 @@
},
{
"from": [
-12.0,
-13.0,
2.0,
-12.0
-13.0
],
"to": [
0.0,
10.0,
0.0
1.0,
12.0,
1.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
8.0
14.0,
10.0
],
"texture": "#crate_b"
},
@@ -101,8 +102,8 @@
"uv": [
0,
0,
12.0,
8.0
14.0,
10.0
],
"texture": "#crate_b"
},
@@ -110,8 +111,8 @@
"uv": [
0,
0,
12.0,
8.0
14.0,
10.0
],
"texture": "#crate_b"
},
@@ -119,8 +120,8 @@
"uv": [
0,
0,
12.0,
8.0
14.0,
10.0
],
"texture": "#crate_b"
},
@@ -128,8 +129,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate_b"
},
@@ -137,8 +138,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate_b"
}
@@ -146,21 +147,21 @@
},
{
"from": [
-12.0,
-13.0,
2.0,
4.0
3.0
],
"to": [
0.0,
1.0,
10.0,
16.0
17.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate_b"
@@ -169,7 +170,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate_b"
@@ -178,7 +179,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate_b"
@@ -187,7 +188,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate_b"
@@ -196,8 +197,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate_b"
},
@@ -205,8 +206,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate_b"
}
@@ -214,21 +215,21 @@
},
{
"from": [
4.0,
3.0,
2.0,
-12.0
-13.0
],
"to": [
16.0,
17.0,
10.0,
0.0
1.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate_b"
@@ -237,7 +238,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate_b"
@@ -246,7 +247,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate_b"
@@ -255,7 +256,7 @@
"uv": [
0,
0,
12.0,
14.0,
8.0
],
"texture": "#crate_b"
@@ -264,8 +265,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate_b"
},
@@ -273,13 +274,149 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#crate_b"
}
}
},
{
"from": [
-14.0,
2.0,
27.0
],
"to": [
30.0,
5.0,
29.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
16,
2.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
16,
2.0
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
-14.0,
2.0,
-14.0
],
"to": [
-12.0,
5.0,
28.0
],
"faces": {
"north": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
2.0,
16
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
2.0,
16
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
6.0,
@@ -485,4 +622,4 @@
}
}
]
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -2,7 +2,7 @@
"ambientocclusion": false,
"textures": {
"bare_barrel": "airdef:block/bare_barrel",
"flecktarn": "airdef:block/flecktarn",
"pilot_nato": "airdef:block/pilot_nato",
"dark_metal": "airdef:block/dark_metal",
"particle": "airdef:block/bare_barrel"
},
@@ -162,7 +162,7 @@
5.0,
5.5
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"south": {
"uv": [
@@ -171,7 +171,7 @@
5.0,
5.5
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"east": {
"uv": [
@@ -180,7 +180,7 @@
12.0,
5.5
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"west": {
"uv": [
@@ -189,7 +189,7 @@
12.0,
5.5
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"up": {
"uv": [
@@ -198,7 +198,7 @@
5.0,
12.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"down": {
"uv": [
@@ -207,7 +207,7 @@
5.0,
12.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
}
}
},
@@ -230,7 +230,7 @@
5.0,
5.5
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"south": {
"uv": [
@@ -239,7 +239,7 @@
5.0,
5.5
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"east": {
"uv": [
@@ -248,7 +248,7 @@
12.0,
5.5
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"west": {
"uv": [
@@ -257,7 +257,7 @@
12.0,
5.5
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"up": {
"uv": [
@@ -266,7 +266,7 @@
5.0,
12.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"down": {
"uv": [
@@ -275,7 +275,7 @@
5.0,
12.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
}
}
},
@@ -416,4 +416,4 @@
}
}
]
}
}
@@ -2,7 +2,7 @@
"ambientocclusion": false,
"textures": {
"bare_barrel_b": "airdef:block/bare_barrel_b",
"flecktarn_b": "airdef:block/flecktarn_b",
"pilot_nato_b": "airdef:block/pilot_nato_b",
"dark_metal_b": "airdef:block/dark_metal_b",
"particle": "airdef:block/bare_barrel_b"
},
@@ -162,7 +162,7 @@
5.0,
5.5
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"south": {
"uv": [
@@ -171,7 +171,7 @@
5.0,
5.5
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"east": {
"uv": [
@@ -180,7 +180,7 @@
12.0,
5.5
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"west": {
"uv": [
@@ -189,7 +189,7 @@
12.0,
5.5
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"up": {
"uv": [
@@ -198,7 +198,7 @@
5.0,
12.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"down": {
"uv": [
@@ -207,7 +207,7 @@
5.0,
12.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
}
}
},
@@ -230,7 +230,7 @@
5.0,
5.5
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"south": {
"uv": [
@@ -239,7 +239,7 @@
5.0,
5.5
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"east": {
"uv": [
@@ -248,7 +248,7 @@
12.0,
5.5
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"west": {
"uv": [
@@ -257,7 +257,7 @@
12.0,
5.5
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"up": {
"uv": [
@@ -266,7 +266,7 @@
5.0,
12.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"down": {
"uv": [
@@ -275,7 +275,7 @@
5.0,
12.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
}
}
},
@@ -348,4 +348,4 @@
}
}
]
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,25 +1,23 @@
{
"ambientocclusion": false,
"textures": {
"flecktarn_s21": "airdef:block/flecktarn_s21",
"flecktarn": "airdef:block/flecktarn",
"pilot_nato": "airdef:block/pilot_nato",
"radar_face": "airdef:block/radar_face",
"metal": "airdef:block/metal",
"mk_de": "airdef:block/mk_de",
"bare_antenna": "airdef:block/bare_antenna",
"dark_metal": "airdef:block/dark_metal",
"particle": "airdef:block/flecktarn_s21"
"mk_de": "airdef:block/mk_de",
"particle": "airdef:block/pilot_nato"
},
"elements": [
{
"from": [
-4.0,
0.0,
-6.0
-5.0
],
"to": [
20.0,
12.0,
5.0,
16.0
],
"faces": {
@@ -28,36 +26,36 @@
0,
0,
16,
12.0
5.0
],
"texture": "#flecktarn_s21"
"texture": "#pilot_nato"
},
"south": {
"uv": [
0,
0,
16,
12.0
5.0
],
"texture": "#flecktarn_s21"
"texture": "#pilot_nato"
},
"east": {
"uv": [
0,
0,
16,
12.0
5.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"west": {
"uv": [
0,
0,
16,
12.0
5.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"up": {
"uv": [
@@ -66,7 +64,7 @@
16,
16
],
"texture": "#flecktarn_s21"
"texture": "#pilot_nato"
},
"down": {
"uv": [
@@ -75,7 +73,75 @@
16,
16
],
"texture": "#flecktarn_s21"
"texture": "#pilot_nato"
}
}
},
{
"from": [
-2.5,
5.0,
-5.0
],
"to": [
18.5,
12.0,
15.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
7.0
],
"texture": "#pilot_nato"
},
"south": {
"uv": [
0,
0,
16,
7.0
],
"texture": "#pilot_nato"
},
"east": {
"uv": [
0,
0,
16,
7.0
],
"texture": "#pilot_nato"
},
"west": {
"uv": [
0,
0,
16,
7.0
],
"texture": "#pilot_nato"
},
"up": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_nato"
},
"down": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_nato"
}
}
},
@@ -87,7 +153,7 @@
],
"to": [
18.0,
14.0,
13.0,
14.0
],
"faces": {
@@ -96,36 +162,36 @@
0,
0,
16,
2.0
1.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"south": {
"uv": [
0,
0,
16,
2.0
1.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"east": {
"uv": [
0,
0,
16,
2.0
1.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"west": {
"uv": [
0,
0,
16,
2.0
1.0
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"up": {
"uv": [
@@ -134,7 +200,7 @@
16,
16
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
},
"down": {
"uv": [
@@ -143,7 +209,7 @@
16,
16
],
"texture": "#flecktarn"
"texture": "#pilot_nato"
}
}
},
@@ -218,7 +284,7 @@
{
"from": [
7.0,
14.0,
13.0,
10.0
],
"to": [
@@ -232,7 +298,7 @@
0,
0,
2.0,
4.0
5.0
],
"texture": "#metal"
},
@@ -241,7 +307,7 @@
0,
0,
2.0,
4.0
5.0
],
"texture": "#metal"
},
@@ -250,7 +316,7 @@
0,
0,
2.0,
4.0
5.0
],
"texture": "#metal"
},
@@ -259,7 +325,7 @@
0,
0,
2.0,
4.0
5.0
],
"texture": "#metal"
},
@@ -285,150 +351,168 @@
},
{
"from": [
20.0,
3.0,
-5.5
-4.7,
4.8,
-4.0
],
"to": [
20.119999999999997,
6.5,
1.5
-2.5,
10.7,
14.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.25,
3.5
2.2,
5.8999999999999995
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"south": {
"uv": [
0,
0,
0.25,
3.5
2.2,
5.8999999999999995
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"east": {
"uv": [
0,
0,
7.0,
3.5
16,
5.8999999999999995
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"west": {
"uv": [
0,
0,
7.0,
3.5
16,
5.8999999999999995
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"up": {
"uv": [
0,
0,
0.25,
7.0
2.2,
16
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"down": {
"uv": [
0,
0,
0.25,
7.0
2.2,
16
],
"texture": "#mk_de"
"texture": "#pilot_nato"
}
},
"rotation": {
"angle": 22.5,
"axis": "z",
"origin": [
-3.6,
7.75,
5.0
]
}
},
{
"from": [
-4.119999999999997,
3.0,
-5.5
18.5,
4.8,
-4.0
],
"to": [
-4.0,
6.5,
1.5
20.7,
10.7,
14.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.25,
3.5
2.1999999999999993,
5.8999999999999995
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"south": {
"uv": [
0,
0,
0.25,
3.5
2.1999999999999993,
5.8999999999999995
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"east": {
"uv": [
0,
0,
7.0,
3.5
16,
5.8999999999999995
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"west": {
"uv": [
0,
0,
7.0,
3.5
16,
5.8999999999999995
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"up": {
"uv": [
0,
0,
0.25,
7.0
2.1999999999999993,
16
],
"texture": "#mk_de"
"texture": "#pilot_nato"
},
"down": {
"uv": [
0,
0,
0.25,
7.0
2.1999999999999993,
16
],
"texture": "#mk_de"
"texture": "#pilot_nato"
}
},
"rotation": {
"angle": -22.5,
"axis": "z",
"origin": [
19.6,
7.75,
5.0
]
}
},
{
"from": [
5.5,
14.0,
0.0,
13.05,
2.0
],
"to": [
10.5,
14.8,
7.0
5.0,
13.7,
8.0
],
"faces": {
"north": {
@@ -436,143 +520,75 @@
0,
0,
5.0,
0.8000000000000007
0.6499999999999986
],
"texture": "#metal"
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
5.0,
0.8000000000000007
0.6499999999999986
],
"texture": "#metal"
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
5.0,
0.8000000000000007
6.0,
0.6499999999999986
],
"texture": "#metal"
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
5.0,
0.8000000000000007
6.0,
0.6499999999999986
],
"texture": "#metal"
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
5.0,
5.0
6.0
],
"texture": "#metal"
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
5.0,
5.0
6.0
],
"texture": "#metal"
"texture": "#dark_metal"
}
}
},
{
"from": [
2.0,
14.0,
5.0
],
"to": [
3.0,
16.0,
6.0
],
"faces": {
"north": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#bare_antenna"
},
"south": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#bare_antenna"
},
"east": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#bare_antenna"
},
"west": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#bare_antenna"
},
"up": {
"uv": [
0,
0,
1.0,
1.0
],
"texture": "#bare_antenna"
},
"down": {
"uv": [
0,
0,
1.0,
1.0
],
"texture": "#bare_antenna"
}
}
},
{
"from": [
-4.800000000000001,
7.0,
-5.0
],
"to": [
-4.0,
10.0,
-2.0
13.05,
2.0
],
"to": [
15.0,
13.7,
8.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.8000000000000007,
3.0
5.0,
0.6499999999999986
],
"texture": "#dark_metal"
},
@@ -580,8 +596,8 @@
"uv": [
0,
0,
0.8000000000000007,
3.0
5.0,
0.6499999999999986
],
"texture": "#dark_metal"
},
@@ -589,8 +605,8 @@
"uv": [
0,
0,
3.0,
3.0
6.0,
0.6499999999999986
],
"texture": "#dark_metal"
},
@@ -598,8 +614,8 @@
"uv": [
0,
0,
3.0,
3.0
6.0,
0.6499999999999986
],
"texture": "#dark_metal"
},
@@ -607,8 +623,8 @@
"uv": [
0,
0,
0.8000000000000007,
3.0
5.0,
6.0
],
"texture": "#dark_metal"
},
@@ -616,8 +632,8 @@
"uv": [
0,
0,
0.8000000000000007,
3.0
5.0,
6.0
],
"texture": "#dark_metal"
}
@@ -625,207 +641,139 @@
},
{
"from": [
20.0,
7.0,
-5.0
18.5,
6.0,
-4.0
],
"to": [
20.8,
10.0,
-2.0
18.619999999999997,
9.0,
2.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.8000000000000007,
0.25,
3.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"south": {
"uv": [
0,
0,
0.8000000000000007,
0.25,
3.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"east": {
"uv": [
0,
0,
3.0,
6.0,
3.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"west": {
"uv": [
0,
0,
3.0,
6.0,
3.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"up": {
"uv": [
0,
0,
0.8000000000000007,
3.0
0.25,
6.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"down": {
"uv": [
0,
0,
0.8000000000000007,
3.0
0.25,
6.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
}
}
},
{
"from": [
-4.800000000000001,
7.0,
-1.5
-2.6199999999999974,
6.0,
-4.0
],
"to": [
-4.0,
10.0,
0.5
-2.5,
9.0,
2.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.8000000000000007,
0.25,
3.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"south": {
"uv": [
0,
0,
0.8000000000000007,
0.25,
3.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"east": {
"uv": [
0,
0,
2.0,
6.0,
3.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"west": {
"uv": [
0,
0,
2.0,
6.0,
3.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"up": {
"uv": [
0,
0,
0.8000000000000007,
2.0
0.25,
6.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
},
"down": {
"uv": [
0,
0,
0.8000000000000007,
2.0
0.25,
6.0
],
"texture": "#dark_metal"
}
}
},
{
"from": [
20.0,
7.0,
-1.5
],
"to": [
20.8,
10.0,
0.5
],
"faces": {
"north": {
"uv": [
0,
0,
0.8000000000000007,
3.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
0.8000000000000007,
3.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
0.8000000000000007,
2.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
0.8000000000000007,
2.0
],
"texture": "#dark_metal"
"texture": "#mk_de"
}
}
}
]
}
}
@@ -1,25 +1,23 @@
{
"ambientocclusion": false,
"textures": {
"flecktarn_s21_b": "airdef:block/flecktarn_s21_b",
"flecktarn_b": "airdef:block/flecktarn_b",
"pilot_nato_b": "airdef:block/pilot_nato_b",
"radar_face_b": "airdef:block/radar_face_b",
"metal_b": "airdef:block/metal_b",
"mk_de_b": "airdef:block/mk_de_b",
"bare_antenna_b": "airdef:block/bare_antenna_b",
"dark_metal_b": "airdef:block/dark_metal_b",
"particle": "airdef:block/flecktarn_s21_b"
"mk_de_b": "airdef:block/mk_de_b",
"particle": "airdef:block/pilot_nato_b"
},
"elements": [
{
"from": [
-4.0,
0.0,
-6.0
-5.0
],
"to": [
20.0,
12.0,
5.0,
16.0
],
"faces": {
@@ -28,36 +26,36 @@
0,
0,
16,
12.0
5.0
],
"texture": "#flecktarn_s21_b"
"texture": "#pilot_nato_b"
},
"south": {
"uv": [
0,
0,
16,
12.0
5.0
],
"texture": "#flecktarn_s21_b"
"texture": "#pilot_nato_b"
},
"east": {
"uv": [
0,
0,
16,
12.0
5.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"west": {
"uv": [
0,
0,
16,
12.0
5.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"up": {
"uv": [
@@ -66,7 +64,7 @@
16,
16
],
"texture": "#flecktarn_s21_b"
"texture": "#pilot_nato_b"
},
"down": {
"uv": [
@@ -75,7 +73,75 @@
16,
16
],
"texture": "#flecktarn_s21_b"
"texture": "#pilot_nato_b"
}
}
},
{
"from": [
-2.5,
5.0,
-5.0
],
"to": [
18.5,
12.0,
15.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
7.0
],
"texture": "#pilot_nato_b"
},
"south": {
"uv": [
0,
0,
16,
7.0
],
"texture": "#pilot_nato_b"
},
"east": {
"uv": [
0,
0,
16,
7.0
],
"texture": "#pilot_nato_b"
},
"west": {
"uv": [
0,
0,
16,
7.0
],
"texture": "#pilot_nato_b"
},
"up": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_nato_b"
},
"down": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_nato_b"
}
}
},
@@ -87,7 +153,7 @@
],
"to": [
18.0,
14.0,
13.0,
14.0
],
"faces": {
@@ -96,36 +162,36 @@
0,
0,
16,
2.0
1.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"south": {
"uv": [
0,
0,
16,
2.0
1.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"east": {
"uv": [
0,
0,
16,
2.0
1.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"west": {
"uv": [
0,
0,
16,
2.0
1.0
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"up": {
"uv": [
@@ -134,7 +200,7 @@
16,
16
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
},
"down": {
"uv": [
@@ -143,7 +209,7 @@
16,
16
],
"texture": "#flecktarn_b"
"texture": "#pilot_nato_b"
}
}
},
@@ -218,7 +284,7 @@
{
"from": [
7.0,
14.0,
13.0,
10.0
],
"to": [
@@ -232,7 +298,7 @@
0,
0,
2.0,
4.0
5.0
],
"texture": "#metal_b"
},
@@ -241,7 +307,7 @@
0,
0,
2.0,
4.0
5.0
],
"texture": "#metal_b"
},
@@ -250,7 +316,7 @@
0,
0,
2.0,
4.0
5.0
],
"texture": "#metal_b"
},
@@ -259,7 +325,7 @@
0,
0,
2.0,
4.0
5.0
],
"texture": "#metal_b"
},
@@ -285,226 +351,244 @@
},
{
"from": [
20.0,
3.0,
-5.5
-4.7,
4.8,
-4.0
],
"to": [
20.119999999999997,
6.5,
1.5
-2.5,
10.7,
14.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.25,
3.5
2.2,
5.8999999999999995
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"south": {
"uv": [
0,
0,
0.25,
3.5
2.2,
5.8999999999999995
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"east": {
"uv": [
0,
0,
7.0,
3.5
16,
5.8999999999999995
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"west": {
"uv": [
0,
0,
7.0,
3.5
16,
5.8999999999999995
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"up": {
"uv": [
0,
0,
0.25,
7.0
2.2,
16
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"down": {
"uv": [
0,
0,
0.25,
7.0
2.2,
16
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
}
},
"rotation": {
"angle": 22.5,
"axis": "z",
"origin": [
-3.6,
7.75,
5.0
]
}
},
{
"from": [
-4.119999999999997,
3.0,
-5.5
18.5,
4.8,
-4.0
],
"to": [
-4.0,
6.5,
1.5
20.7,
10.7,
14.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.25,
3.5
2.1999999999999993,
5.8999999999999995
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"south": {
"uv": [
0,
0,
0.25,
3.5
2.1999999999999993,
5.8999999999999995
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"east": {
"uv": [
0,
0,
7.0,
3.5
16,
5.8999999999999995
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"west": {
"uv": [
0,
0,
7.0,
3.5
16,
5.8999999999999995
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"up": {
"uv": [
0,
0,
0.25,
7.0
2.1999999999999993,
16
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
},
"down": {
"uv": [
0,
0,
0.25,
7.0
2.1999999999999993,
16
],
"texture": "#mk_de_b"
"texture": "#pilot_nato_b"
}
},
"rotation": {
"angle": -22.5,
"axis": "z",
"origin": [
19.6,
7.75,
5.0
]
}
},
{
"from": [
2.0,
14.0,
5.0
0.0,
13.05,
2.0
],
"to": [
3.0,
16.0,
6.0
5.0,
13.7,
8.0
],
"faces": {
"north": {
"uv": [
0,
0,
1.0,
2.0
5.0,
0.6499999999999986
],
"texture": "#bare_antenna_b"
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
1.0,
2.0
5.0,
0.6499999999999986
],
"texture": "#bare_antenna_b"
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
1.0,
2.0
6.0,
0.6499999999999986
],
"texture": "#bare_antenna_b"
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
1.0,
2.0
6.0,
0.6499999999999986
],
"texture": "#bare_antenna_b"
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
1.0,
1.0
5.0,
6.0
],
"texture": "#bare_antenna_b"
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
1.0,
1.0
5.0,
6.0
],
"texture": "#bare_antenna_b"
"texture": "#dark_metal_b"
}
}
},
{
"from": [
-4.800000000000001,
7.0,
-5.0
],
"to": [
-4.0,
10.0,
-2.0
13.05,
2.0
],
"to": [
15.0,
13.7,
8.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.8000000000000007,
3.0
5.0,
0.6499999999999986
],
"texture": "#dark_metal_b"
},
@@ -512,8 +596,8 @@
"uv": [
0,
0,
0.8000000000000007,
3.0
5.0,
0.6499999999999986
],
"texture": "#dark_metal_b"
},
@@ -521,8 +605,8 @@
"uv": [
0,
0,
3.0,
3.0
6.0,
0.6499999999999986
],
"texture": "#dark_metal_b"
},
@@ -530,8 +614,8 @@
"uv": [
0,
0,
3.0,
3.0
6.0,
0.6499999999999986
],
"texture": "#dark_metal_b"
},
@@ -539,8 +623,8 @@
"uv": [
0,
0,
0.8000000000000007,
3.0
5.0,
6.0
],
"texture": "#dark_metal_b"
},
@@ -548,8 +632,8 @@
"uv": [
0,
0,
0.8000000000000007,
3.0
5.0,
6.0
],
"texture": "#dark_metal_b"
}
@@ -557,139 +641,71 @@
},
{
"from": [
20.0,
7.0,
-5.0
-2.6199999999999974,
6.0,
-4.0
],
"to": [
20.8,
10.0,
-2.0
-2.5,
9.0,
2.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.8000000000000007,
0.25,
3.0
],
"texture": "#dark_metal_b"
"texture": "#mk_de_b"
},
"south": {
"uv": [
0,
0,
0.8000000000000007,
0.25,
3.0
],
"texture": "#dark_metal_b"
"texture": "#mk_de_b"
},
"east": {
"uv": [
0,
0,
3.0,
6.0,
3.0
],
"texture": "#dark_metal_b"
"texture": "#mk_de_b"
},
"west": {
"uv": [
0,
0,
3.0,
6.0,
3.0
],
"texture": "#dark_metal_b"
"texture": "#mk_de_b"
},
"up": {
"uv": [
0,
0,
0.8000000000000007,
3.0
0.25,
6.0
],
"texture": "#dark_metal_b"
"texture": "#mk_de_b"
},
"down": {
"uv": [
0,
0,
0.8000000000000007,
3.0
0.25,
6.0
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
-4.800000000000001,
7.0,
-1.5
],
"to": [
-4.0,
10.0,
0.5
],
"faces": {
"north": {
"uv": [
0,
0,
0.8000000000000007,
3.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
0.8000000000000007,
3.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
2.0,
3.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
0.8000000000000007,
2.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
0.8000000000000007,
2.0
],
"texture": "#dark_metal_b"
"texture": "#mk_de_b"
}
}
}
]
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -686,6 +686,142 @@
"texture": "#dark_metal"
}
}
},
{
"from": [
-1.9,
0.0,
-2.0
],
"to": [
17.9,
9.0,
-1.5
],
"faces": {
"north": {
"uv": [
0,
0,
16,
9.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
16,
9.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
16,
0.5
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
16,
0.5
],
"texture": "#dark_metal"
}
}
},
{
"from": [
-1.9,
0.0,
22.0
],
"to": [
17.9,
9.0,
22.5
],
"faces": {
"north": {
"uv": [
0,
0,
16,
9.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
16,
9.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
16,
0.5
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
16,
0.5
],
"texture": "#dark_metal"
}
}
}
]
}
}
@@ -686,6 +686,142 @@
"texture": "#dark_metal_b"
}
}
},
{
"from": [
-1.9,
0.0,
-2.0
],
"to": [
17.9,
9.0,
-1.5
],
"faces": {
"north": {
"uv": [
0,
0,
16,
9.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
16,
9.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
16,
0.5
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
16,
0.5
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
-1.9,
0.0,
22.0
],
"to": [
17.9,
9.0,
22.5
],
"faces": {
"north": {
"uv": [
0,
0,
16,
9.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
16,
9.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
16,
0.5
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
16,
0.5
],
"texture": "#dark_metal_b"
}
}
}
]
}
}
+598 -54
View File
@@ -741,8 +741,8 @@
2.0
],
"to": [
22.0,
7.6,
13.55,
7.5,
11.0
],
"faces": {
@@ -750,8 +750,8 @@
"uv": [
0,
0,
11.5,
0.6999999999999993
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -759,8 +759,8 @@
"uv": [
0,
0,
11.5,
0.6999999999999993
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -769,7 +769,7 @@
0,
0,
9.0,
0.6999999999999993
0.5999999999999996
],
"texture": "#kh101"
},
@@ -778,7 +778,7 @@
0,
0,
9.0,
0.6999999999999993
0.5999999999999996
],
"texture": "#kh101"
},
@@ -786,7 +786,7 @@
"uv": [
0,
0,
11.5,
3.0500000000000007,
9.0
],
"texture": "#kh101"
@@ -795,7 +795,7 @@
"uv": [
0,
0,
11.5,
3.0500000000000007,
9.0
],
"texture": "#kh101_belly"
@@ -804,13 +804,13 @@
},
{
"from": [
-6.0,
2.4499999999999993,
6.9,
2.0
],
"to": [
5.5,
7.6,
7.5,
11.0
],
"faces": {
@@ -818,8 +818,8 @@
"uv": [
0,
0,
11.5,
0.6999999999999993
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -827,8 +827,8 @@
"uv": [
0,
0,
11.5,
0.6999999999999993
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -837,7 +837,7 @@
0,
0,
9.0,
0.6999999999999993
0.5999999999999996
],
"texture": "#kh101"
},
@@ -846,7 +846,7 @@
0,
0,
9.0,
0.6999999999999993
0.5999999999999996
],
"texture": "#kh101"
},
@@ -854,7 +854,7 @@
"uv": [
0,
0,
11.5,
3.0500000000000007,
9.0
],
"texture": "#kh101"
@@ -863,7 +863,7 @@
"uv": [
0,
0,
11.5,
3.0500000000000007,
9.0
],
"texture": "#kh101_belly"
@@ -872,22 +872,22 @@
},
{
"from": [
22.0,
13.5,
6.9,
5.0
2.65
],
"to": [
28.5,
7.4,
11.0
16.55,
7.5,
10.88
],
"faces": {
"north": {
"uv": [
0,
0,
6.5,
0.5
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -895,8 +895,8 @@
"uv": [
0,
0,
6.5,
0.5
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -904,8 +904,8 @@
"uv": [
0,
0,
6.0,
0.5
8.23,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -913,8 +913,8 @@
"uv": [
0,
0,
6.0,
0.5
8.23,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -922,8 +922,8 @@
"uv": [
0,
0,
6.5,
6.0
3.0500000000000007,
8.23
],
"texture": "#kh101"
},
@@ -931,8 +931,552 @@
"uv": [
0,
0,
6.5,
6.0
3.0500000000000007,
8.23
],
"texture": "#kh101_belly"
}
}
},
{
"from": [
-0.5500000000000007,
6.9,
2.65
],
"to": [
2.5,
7.5,
10.88
],
"faces": {
"north": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"south": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"east": {
"uv": [
0,
0,
8.23,
0.5999999999999996
],
"texture": "#kh101"
},
"west": {
"uv": [
0,
0,
8.23,
0.5999999999999996
],
"texture": "#kh101"
},
"up": {
"uv": [
0,
0,
3.0500000000000007,
8.23
],
"texture": "#kh101"
},
"down": {
"uv": [
0,
0,
3.0500000000000007,
8.23
],
"texture": "#kh101_belly"
}
}
},
{
"from": [
16.5,
6.9,
3.3
],
"to": [
19.55,
7.5,
10.76
],
"faces": {
"north": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"south": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"east": {
"uv": [
0,
0,
7.46,
0.5999999999999996
],
"texture": "#kh101"
},
"west": {
"uv": [
0,
0,
7.46,
0.5999999999999996
],
"texture": "#kh101"
},
"up": {
"uv": [
0,
0,
3.0500000000000007,
7.46
],
"texture": "#kh101"
},
"down": {
"uv": [
0,
0,
3.0500000000000007,
7.46
],
"texture": "#kh101_belly"
}
}
},
{
"from": [
-3.5500000000000007,
6.9,
3.3
],
"to": [
-0.5,
7.5,
10.76
],
"faces": {
"north": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"south": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"east": {
"uv": [
0,
0,
7.46,
0.5999999999999996
],
"texture": "#kh101"
},
"west": {
"uv": [
0,
0,
7.46,
0.5999999999999996
],
"texture": "#kh101"
},
"up": {
"uv": [
0,
0,
3.0500000000000007,
7.46
],
"texture": "#kh101"
},
"down": {
"uv": [
0,
0,
3.0500000000000007,
7.46
],
"texture": "#kh101_belly"
}
}
},
{
"from": [
19.5,
6.9,
3.95
],
"to": [
22.55,
7.5,
10.64
],
"faces": {
"north": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"south": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"east": {
"uv": [
0,
0,
6.69,
0.5999999999999996
],
"texture": "#kh101"
},
"west": {
"uv": [
0,
0,
6.69,
0.5999999999999996
],
"texture": "#kh101"
},
"up": {
"uv": [
0,
0,
3.0500000000000007,
6.69
],
"texture": "#kh101"
},
"down": {
"uv": [
0,
0,
3.0500000000000007,
6.69
],
"texture": "#kh101_belly"
}
}
},
{
"from": [
-6.550000000000001,
6.9,
3.95
],
"to": [
-3.5,
7.5,
10.64
],
"faces": {
"north": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"south": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"east": {
"uv": [
0,
0,
6.69,
0.5999999999999996
],
"texture": "#kh101"
},
"west": {
"uv": [
0,
0,
6.69,
0.5999999999999996
],
"texture": "#kh101"
},
"up": {
"uv": [
0,
0,
3.0500000000000007,
6.69
],
"texture": "#kh101"
},
"down": {
"uv": [
0,
0,
3.0500000000000007,
6.69
],
"texture": "#kh101_belly"
}
}
},
{
"from": [
22.5,
6.9,
4.6
],
"to": [
25.55,
7.5,
10.52
],
"faces": {
"north": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"south": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"east": {
"uv": [
0,
0,
5.92,
0.5999999999999996
],
"texture": "#kh101"
},
"west": {
"uv": [
0,
0,
5.92,
0.5999999999999996
],
"texture": "#kh101"
},
"up": {
"uv": [
0,
0,
3.0500000000000007,
5.92
],
"texture": "#kh101"
},
"down": {
"uv": [
0,
0,
3.0500000000000007,
5.92
],
"texture": "#kh101_belly"
}
}
},
{
"from": [
-9.55,
6.9,
4.6
],
"to": [
-6.5,
7.5,
10.52
],
"faces": {
"north": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"south": {
"uv": [
0,
0,
3.0500000000000007,
0.5999999999999996
],
"texture": "#kh101"
},
"east": {
"uv": [
0,
0,
5.92,
0.5999999999999996
],
"texture": "#kh101"
},
"west": {
"uv": [
0,
0,
5.92,
0.5999999999999996
],
"texture": "#kh101"
},
"up": {
"uv": [
0,
0,
3.0500000000000007,
5.92
],
"texture": "#kh101"
},
"down": {
"uv": [
0,
0,
3.0500000000000007,
5.92
],
"texture": "#kh101_belly"
}
}
},
{
"from": [
25.5,
6.9,
5.25
],
"to": [
28.5,
7.5,
10.4
],
"faces": {
"north": {
"uv": [
0,
0,
3.0,
0.5999999999999996
],
"texture": "#kh101"
},
"south": {
"uv": [
0,
0,
3.0,
0.5999999999999996
],
"texture": "#kh101"
},
"east": {
"uv": [
0,
0,
5.15,
0.5999999999999996
],
"texture": "#kh101"
},
"west": {
"uv": [
0,
0,
5.15,
0.5999999999999996
],
"texture": "#kh101"
},
"up": {
"uv": [
0,
0,
3.0,
5.15
],
"texture": "#kh101"
},
"down": {
"uv": [
0,
0,
3.0,
5.15
],
"texture": "#kh101_belly"
}
@@ -942,20 +1486,20 @@
"from": [
-12.5,
6.9,
5.0
5.25
],
"to": [
-6.0,
7.4,
11.0
-9.5,
7.5,
10.4
],
"faces": {
"north": {
"uv": [
0,
0,
6.5,
0.5
3.0,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -963,8 +1507,8 @@
"uv": [
0,
0,
6.5,
0.5
3.0,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -972,8 +1516,8 @@
"uv": [
0,
0,
6.0,
0.5
5.15,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -981,8 +1525,8 @@
"uv": [
0,
0,
6.0,
0.5
5.15,
0.5999999999999996
],
"texture": "#kh101"
},
@@ -990,8 +1534,8 @@
"uv": [
0,
0,
6.5,
6.0
3.0,
5.15
],
"texture": "#kh101"
},
@@ -999,8 +1543,8 @@
"uv": [
0,
0,
6.5,
6.0
3.0,
5.15
],
"texture": "#kh101_belly"
}
@@ -1551,4 +2095,4 @@
}
}
]
}
}
File diff suppressed because it is too large Load Diff
@@ -550,6 +550,142 @@
"texture": "#dark_metal"
}
}
},
{
"from": [
0.6,
0.0,
-2.0
],
"to": [
15.4,
9.0,
-1.5
],
"faces": {
"north": {
"uv": [
0,
0,
14.8,
9.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
14.8,
9.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
14.8,
0.5
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
14.8,
0.5
],
"texture": "#dark_metal"
}
}
},
{
"from": [
0.6,
0.0,
22.0
],
"to": [
15.4,
9.0,
22.5
],
"faces": {
"north": {
"uv": [
0,
0,
14.8,
9.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
14.8,
9.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
14.8,
0.5
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
14.8,
0.5
],
"texture": "#dark_metal"
}
}
}
]
}
}
@@ -550,6 +550,142 @@
"texture": "#dark_metal_b"
}
}
},
{
"from": [
0.6,
0.0,
-2.0
],
"to": [
15.4,
9.0,
-1.5
],
"faces": {
"north": {
"uv": [
0,
0,
14.8,
9.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
14.8,
9.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
14.8,
0.5
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
14.8,
0.5
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
0.6,
0.0,
22.0
],
"to": [
15.4,
9.0,
22.5
],
"faces": {
"north": {
"uv": [
0,
0,
14.8,
9.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
14.8,
9.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
0.5,
9.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
14.8,
0.5
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
14.8,
0.5
],
"texture": "#dark_metal_b"
}
}
}
]
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -2,9 +2,7 @@
"ambientocclusion": false,
"textures": {
"tubes6": "airdef:block/tubes6",
"ru_green": "airdef:block/ru_green",
"ru_green_s21": "airdef:block/ru_green_s21",
"ru_green_s12": "airdef:block/ru_green_s12",
"pilot_olive": "airdef:block/pilot_olive",
"bare_barrel": "airdef:block/bare_barrel",
"dark_metal": "airdef:block/dark_metal",
"particle": "airdef:block/tubes6"
@@ -38,7 +36,7 @@
8.0,
10.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"east": {
"uv": [
@@ -47,7 +45,7 @@
16,
10.0
],
"texture": "#ru_green_s21"
"texture": "#pilot_olive"
},
"west": {
"uv": [
@@ -56,7 +54,7 @@
16,
10.0
],
"texture": "#ru_green_s21"
"texture": "#pilot_olive"
},
"up": {
"uv": [
@@ -65,7 +63,7 @@
8.0,
16
],
"texture": "#ru_green_s12"
"texture": "#pilot_olive"
},
"down": {
"uv": [
@@ -74,7 +72,7 @@
8.0,
16
],
"texture": "#ru_green_s12"
"texture": "#pilot_olive"
}
}
},
@@ -106,7 +104,7 @@
8.0,
10.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"east": {
"uv": [
@@ -115,7 +113,7 @@
16,
10.0
],
"texture": "#ru_green_s21"
"texture": "#pilot_olive"
},
"west": {
"uv": [
@@ -124,7 +122,7 @@
16,
10.0
],
"texture": "#ru_green_s21"
"texture": "#pilot_olive"
},
"up": {
"uv": [
@@ -133,7 +131,7 @@
8.0,
16
],
"texture": "#ru_green_s12"
"texture": "#pilot_olive"
},
"down": {
"uv": [
@@ -142,7 +140,7 @@
8.0,
16
],
"texture": "#ru_green_s12"
"texture": "#pilot_olive"
}
}
},
@@ -555,4 +553,4 @@
}
}
]
}
}
@@ -2,9 +2,7 @@
"ambientocclusion": false,
"textures": {
"tubes6_b": "airdef:block/tubes6_b",
"ru_green_b": "airdef:block/ru_green_b",
"ru_green_s21_b": "airdef:block/ru_green_s21_b",
"ru_green_s12_b": "airdef:block/ru_green_s12_b",
"pilot_olive_b": "airdef:block/pilot_olive_b",
"bare_barrel_b": "airdef:block/bare_barrel_b",
"dark_metal_b": "airdef:block/dark_metal_b",
"particle": "airdef:block/tubes6_b"
@@ -38,7 +36,7 @@
8.0,
10.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
@@ -47,7 +45,7 @@
16,
10.0
],
"texture": "#ru_green_s21_b"
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
@@ -56,7 +54,7 @@
16,
10.0
],
"texture": "#ru_green_s21_b"
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
@@ -65,7 +63,7 @@
8.0,
16
],
"texture": "#ru_green_s12_b"
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
@@ -74,7 +72,7 @@
8.0,
16
],
"texture": "#ru_green_s12_b"
"texture": "#pilot_olive_b"
}
}
},
@@ -106,7 +104,7 @@
8.0,
10.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
@@ -115,7 +113,7 @@
16,
10.0
],
"texture": "#ru_green_s21_b"
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
@@ -124,7 +122,7 @@
16,
10.0
],
"texture": "#ru_green_s21_b"
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
@@ -133,7 +131,7 @@
8.0,
16
],
"texture": "#ru_green_s12_b"
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
@@ -142,7 +140,7 @@
8.0,
16
],
"texture": "#ru_green_s12_b"
"texture": "#pilot_olive_b"
}
}
},
@@ -555,4 +553,4 @@
}
}
]
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,24 +1,23 @@
{
"ambientocclusion": false,
"textures": {
"ru_green": "airdef:block/ru_green",
"pilot_olive": "airdef:block/pilot_olive",
"radar_face": "airdef:block/radar_face",
"metal": "airdef:block/metal",
"dark_metal": "airdef:block/dark_metal",
"metal": "airdef:block/metal",
"bare_lamp": "airdef:block/bare_lamp",
"mk_ru": "airdef:block/mk_ru",
"particle": "airdef:block/ru_green"
"particle": "airdef:block/pilot_olive"
},
"elements": [
{
"from": [
-2.0,
0.0,
-6.0
-5.0
],
"to": [
18.0,
10.0,
7.0,
16.0
],
"faces": {
@@ -27,36 +26,36 @@
0,
0,
16,
10.0
7.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"south": {
"uv": [
0,
0,
16,
10.0
7.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"east": {
"uv": [
0,
0,
16,
10.0
7.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"west": {
"uv": [
0,
0,
16,
10.0
7.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"up": {
"uv": [
@@ -65,7 +64,7 @@
16,
16
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"down": {
"uv": [
@@ -74,7 +73,75 @@
16,
16
],
"texture": "#ru_green"
"texture": "#pilot_olive"
}
}
},
{
"from": [
0.0,
7.0,
-4.0
],
"to": [
16.0,
10.0,
14.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive"
},
"south": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive"
},
"east": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive"
},
"west": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive"
},
"up": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive"
},
"down": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive"
}
}
},
@@ -146,6 +213,74 @@
}
}
},
{
"from": [
2.0,
1.0,
-6.0
],
"to": [
14.0,
11.0,
-5.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
10.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
12.0,
10.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
1.0,
10.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
1.0,
10.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
12.0,
1.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
12.0,
1.0
],
"texture": "#dark_metal"
}
}
},
{
"from": [
7.0,
@@ -216,12 +351,12 @@
},
{
"from": [
0.0,
1.0,
10.0,
8.0
],
"to": [
16.0,
15.0,
12.0,
16.0
],
@@ -230,19 +365,19 @@
"uv": [
0,
0,
16,
14.0,
2.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"south": {
"uv": [
0,
0,
16,
14.0,
2.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"east": {
"uv": [
@@ -251,7 +386,7 @@
8.0,
2.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"west": {
"uv": [
@@ -260,25 +395,25 @@
8.0,
2.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"up": {
"uv": [
0,
0,
16,
14.0,
8.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
},
"down": {
"uv": [
0,
0,
16,
14.0,
8.0
],
"texture": "#ru_green"
"texture": "#pilot_olive"
}
}
},
@@ -417,210 +552,6 @@
"texture": "#bare_lamp"
}
}
},
{
"from": [
1.0,
12.0,
10.0
],
"to": [
15.0,
12.6,
15.0
],
"faces": {
"north": {
"uv": [
0,
0,
14.0,
0.5999999999999996
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
14.0,
0.5999999999999996
],
"texture": "#metal"
},
"east": {
"uv": [
0,
0,
5.0,
0.5999999999999996
],
"texture": "#metal"
},
"west": {
"uv": [
0,
0,
5.0,
0.5999999999999996
],
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
14.0,
5.0
],
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
14.0,
5.0
],
"texture": "#metal"
}
}
},
{
"from": [
18.0,
3.0,
-4.0
],
"to": [
18.119999999999997,
6.5,
3.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.25,
3.5
],
"texture": "#mk_ru"
},
"south": {
"uv": [
0,
0,
0.25,
3.5
],
"texture": "#mk_ru"
},
"east": {
"uv": [
0,
0,
7.0,
3.5
],
"texture": "#mk_ru"
},
"west": {
"uv": [
0,
0,
7.0,
3.5
],
"texture": "#mk_ru"
},
"up": {
"uv": [
0,
0,
0.25,
7.0
],
"texture": "#mk_ru"
},
"down": {
"uv": [
0,
0,
0.25,
7.0
],
"texture": "#mk_ru"
}
}
},
{
"from": [
-2.1199999999999974,
3.0,
-4.0
],
"to": [
-2.0,
6.5,
3.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.25,
3.5
],
"texture": "#mk_ru"
},
"south": {
"uv": [
0,
0,
0.25,
3.5
],
"texture": "#mk_ru"
},
"east": {
"uv": [
0,
0,
7.0,
3.5
],
"texture": "#mk_ru"
},
"west": {
"uv": [
0,
0,
7.0,
3.5
],
"texture": "#mk_ru"
},
"up": {
"uv": [
0,
0,
0.25,
7.0
],
"texture": "#mk_ru"
},
"down": {
"uv": [
0,
0,
0.25,
7.0
],
"texture": "#mk_ru"
}
}
}
]
}
}
@@ -1,24 +1,22 @@
{
"ambientocclusion": false,
"textures": {
"ru_green_b": "airdef:block/ru_green_b",
"pilot_olive_b": "airdef:block/pilot_olive_b",
"radar_face_b": "airdef:block/radar_face_b",
"metal_b": "airdef:block/metal_b",
"dark_metal_b": "airdef:block/dark_metal_b",
"bare_lamp_b": "airdef:block/bare_lamp_b",
"mk_ru_b": "airdef:block/mk_ru_b",
"particle": "airdef:block/ru_green_b"
"metal_b": "airdef:block/metal_b",
"particle": "airdef:block/pilot_olive_b"
},
"elements": [
{
"from": [
-2.0,
0.0,
-6.0
-5.0
],
"to": [
18.0,
10.0,
7.0,
16.0
],
"faces": {
@@ -27,36 +25,36 @@
0,
0,
16,
10.0
7.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"south": {
"uv": [
0,
0,
16,
10.0
7.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
0,
0,
16,
10.0
7.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
0,
0,
16,
10.0
7.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
@@ -65,7 +63,7 @@
16,
16
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
@@ -74,7 +72,75 @@
16,
16
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
}
}
},
{
"from": [
0.0,
7.0,
-4.0
],
"to": [
16.0,
10.0,
14.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive_b"
},
"south": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
0,
0,
16,
3.0
],
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive_b"
}
}
},
@@ -146,6 +212,74 @@
}
}
},
{
"from": [
2.0,
1.0,
-6.0
],
"to": [
14.0,
11.0,
-5.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
10.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
12.0,
10.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
1.0,
10.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
1.0,
10.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
12.0,
1.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
12.0,
1.0
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
7.0,
@@ -216,12 +350,12 @@
},
{
"from": [
0.0,
1.0,
10.0,
8.0
],
"to": [
16.0,
15.0,
12.0,
16.0
],
@@ -230,19 +364,19 @@
"uv": [
0,
0,
16,
14.0,
2.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"south": {
"uv": [
0,
0,
16,
14.0,
2.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
@@ -251,7 +385,7 @@
8.0,
2.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
@@ -260,25 +394,25 @@
8.0,
2.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
0,
0,
16,
14.0,
8.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
0,
0,
16,
14.0,
8.0
],
"texture": "#ru_green_b"
"texture": "#pilot_olive_b"
}
}
},
@@ -349,210 +483,6 @@
"texture": "#dark_metal_b"
}
}
},
{
"from": [
6.0,
10.5,
-4.4
],
"to": [
10.0,
12.5,
-4.0
],
"faces": {
"north": {
"uv": [
0,
0,
4.0,
2.0
],
"texture": "#bare_lamp_b"
},
"south": {
"uv": [
0,
0,
4.0,
2.0
],
"texture": "#bare_lamp_b"
},
"east": {
"uv": [
0,
0,
0.40000000000000036,
2.0
],
"texture": "#bare_lamp_b"
},
"west": {
"uv": [
0,
0,
0.40000000000000036,
2.0
],
"texture": "#bare_lamp_b"
},
"up": {
"uv": [
0,
0,
4.0,
0.40000000000000036
],
"texture": "#bare_lamp_b"
},
"down": {
"uv": [
0,
0,
4.0,
0.40000000000000036
],
"texture": "#bare_lamp_b"
}
}
},
{
"from": [
1.0,
12.0,
10.0
],
"to": [
15.0,
12.6,
15.0
],
"faces": {
"north": {
"uv": [
0,
0,
14.0,
0.5999999999999996
],
"texture": "#metal_b"
},
"south": {
"uv": [
0,
0,
14.0,
0.5999999999999996
],
"texture": "#metal_b"
},
"east": {
"uv": [
0,
0,
5.0,
0.5999999999999996
],
"texture": "#metal_b"
},
"west": {
"uv": [
0,
0,
5.0,
0.5999999999999996
],
"texture": "#metal_b"
},
"up": {
"uv": [
0,
0,
14.0,
5.0
],
"texture": "#metal_b"
},
"down": {
"uv": [
0,
0,
14.0,
5.0
],
"texture": "#metal_b"
}
}
},
{
"from": [
-2.1199999999999974,
3.0,
-4.0
],
"to": [
-2.0,
6.5,
3.0
],
"faces": {
"north": {
"uv": [
0,
0,
0.25,
3.5
],
"texture": "#mk_ru_b"
},
"south": {
"uv": [
0,
0,
0.25,
3.5
],
"texture": "#mk_ru_b"
},
"east": {
"uv": [
0,
0,
7.0,
3.5
],
"texture": "#mk_ru_b"
},
"west": {
"uv": [
0,
0,
7.0,
3.5
],
"texture": "#mk_ru_b"
},
"up": {
"uv": [
0,
0,
0.25,
7.0
],
"texture": "#mk_ru_b"
},
"down": {
"uv": [
0,
0,
0.25,
7.0
],
"texture": "#mk_ru_b"
}
}
}
]
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,418 @@
{
"ambientocclusion": false,
"textures": {
"dark_metal": "airdef:block/dark_metal",
"metal": "airdef:block/metal",
"particle": "airdef:block/dark_metal"
},
"elements": [
{
"from": [
4.0,
0.0,
4.0
],
"to": [
12.0,
3.0,
12.0
],
"faces": {
"north": {
"uv": [
0,
0,
8.0,
3.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
8.0,
3.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
8.0,
3.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
8.0,
3.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
8.0,
8.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
8.0,
8.0
],
"texture": "#dark_metal"
}
}
},
{
"from": [
5.5,
3.0,
5.5
],
"to": [
10.5,
18.0,
10.5
],
"faces": {
"north": {
"uv": [
0,
0,
5.0,
15.0
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
5.0,
15.0
],
"texture": "#metal"
},
"east": {
"uv": [
0,
0,
5.0,
15.0
],
"texture": "#metal"
},
"west": {
"uv": [
0,
0,
5.0,
15.0
],
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
5.0,
5.0
],
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
5.0,
5.0
],
"texture": "#metal"
}
}
},
{
"from": [
4.5,
18.0,
4.5
],
"to": [
11.5,
21.0,
11.5
],
"faces": {
"north": {
"uv": [
0,
0,
7.0,
3.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
7.0,
3.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
7.0,
3.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
7.0,
3.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
7.0,
7.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
7.0,
7.0
],
"texture": "#dark_metal"
}
}
},
{
"from": [
6.5,
21.0,
6.5
],
"to": [
9.5,
30.0,
9.5
],
"faces": {
"north": {
"uv": [
0,
0,
3.0,
9.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
3.0,
9.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
3.0,
9.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
3.0,
9.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
3.0,
3.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
3.0,
3.0
],
"texture": "#dark_metal"
}
}
},
{
"from": [
5.5,
30.0,
5.5
],
"to": [
10.5,
32.0,
10.5
],
"faces": {
"north": {
"uv": [
0,
0,
5.0,
2.0
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
5.0,
2.0
],
"texture": "#metal"
},
"east": {
"uv": [
0,
0,
5.0,
2.0
],
"texture": "#metal"
},
"west": {
"uv": [
0,
0,
5.0,
2.0
],
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
5.0,
5.0
],
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
5.0,
5.0
],
"texture": "#metal"
}
}
},
{
"from": [
7.0,
31.5,
7.0
],
"to": [
9.0,
32.0,
9.0
],
"faces": {
"north": {
"uv": [
0,
0,
2.0,
0.5
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
2.0,
0.5
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
2.0,
0.5
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
2.0,
0.5
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#dark_metal"
}
}
}
]
}
@@ -0,0 +1,418 @@
{
"ambientocclusion": false,
"textures": {
"dark_metal_b": "airdef:block/dark_metal_b",
"metal_b": "airdef:block/metal_b",
"particle": "airdef:block/dark_metal_b"
},
"elements": [
{
"from": [
4.0,
0.0,
4.0
],
"to": [
12.0,
3.0,
12.0
],
"faces": {
"north": {
"uv": [
0,
0,
8.0,
3.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
8.0,
3.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
8.0,
3.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
8.0,
3.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
8.0,
8.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
8.0,
8.0
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
5.5,
3.0,
5.5
],
"to": [
10.5,
18.0,
10.5
],
"faces": {
"north": {
"uv": [
0,
0,
5.0,
15.0
],
"texture": "#metal_b"
},
"south": {
"uv": [
0,
0,
5.0,
15.0
],
"texture": "#metal_b"
},
"east": {
"uv": [
0,
0,
5.0,
15.0
],
"texture": "#metal_b"
},
"west": {
"uv": [
0,
0,
5.0,
15.0
],
"texture": "#metal_b"
},
"up": {
"uv": [
0,
0,
5.0,
5.0
],
"texture": "#metal_b"
},
"down": {
"uv": [
0,
0,
5.0,
5.0
],
"texture": "#metal_b"
}
}
},
{
"from": [
4.5,
18.0,
4.5
],
"to": [
11.5,
21.0,
11.5
],
"faces": {
"north": {
"uv": [
0,
0,
7.0,
3.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
7.0,
3.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
7.0,
3.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
7.0,
3.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
7.0,
7.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
7.0,
7.0
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
6.5,
21.0,
6.5
],
"to": [
9.5,
30.0,
9.5
],
"faces": {
"north": {
"uv": [
0,
0,
3.0,
9.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
3.0,
9.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
3.0,
9.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
3.0,
9.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
3.0,
3.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
3.0,
3.0
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
5.5,
30.0,
5.5
],
"to": [
10.5,
32.0,
10.5
],
"faces": {
"north": {
"uv": [
0,
0,
5.0,
2.0
],
"texture": "#metal_b"
},
"south": {
"uv": [
0,
0,
5.0,
2.0
],
"texture": "#metal_b"
},
"east": {
"uv": [
0,
0,
5.0,
2.0
],
"texture": "#metal_b"
},
"west": {
"uv": [
0,
0,
5.0,
2.0
],
"texture": "#metal_b"
},
"up": {
"uv": [
0,
0,
5.0,
5.0
],
"texture": "#metal_b"
},
"down": {
"uv": [
0,
0,
5.0,
5.0
],
"texture": "#metal_b"
}
}
},
{
"from": [
7.0,
31.5,
7.0
],
"to": [
9.0,
32.0,
9.0
],
"faces": {
"north": {
"uv": [
0,
0,
2.0,
0.5
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
2.0,
0.5
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
2.0,
0.5
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
2.0,
0.5
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
2.0,
2.0
],
"texture": "#dark_metal_b"
}
}
}
]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -19,15 +19,6 @@
32.0
],
"faces": {
"north": {
"uv": [
0,
0,
9.5,
9.5
],
"texture": "#tube_cap"
},
"south": {
"uv": [
0,
@@ -87,15 +78,6 @@
32.0
],
"faces": {
"north": {
"uv": [
0,
0,
9.5,
9.5
],
"texture": "#tube_cap"
},
"south": {
"uv": [
0,
@@ -19,15 +19,6 @@
32.0
],
"faces": {
"north": {
"uv": [
0,
0,
9.5,
9.5
],
"texture": "#tube_cap_b"
},
"south": {
"uv": [
0,
@@ -87,15 +78,6 @@
32.0
],
"faces": {
"north": {
"uv": [
0,
0,
9.5,
9.5
],
"texture": "#tube_cap_b"
},
"south": {
"uv": [
0,
@@ -2,27 +2,28 @@
"ambientocclusion": false,
"textures": {
"dark_metal": "airdef:block/dark_metal",
"metal": "airdef:block/metal",
"particle": "airdef:block/dark_metal"
},
"elements": [
{
"from": [
2.0,
1.0,
0.0,
2.0
1.0
],
"to": [
14.0,
3.0,
14.0
15.0,
2.0,
15.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
3.0
14.0,
2.0
],
"texture": "#dark_metal"
},
@@ -30,8 +31,8 @@
"uv": [
0,
0,
12.0,
3.0
14.0,
2.0
],
"texture": "#dark_metal"
},
@@ -39,8 +40,8 @@
"uv": [
0,
0,
12.0,
3.0
14.0,
2.0
],
"texture": "#dark_metal"
},
@@ -48,8 +49,8 @@
"uv": [
0,
0,
12.0,
3.0
14.0,
2.0
],
"texture": "#dark_metal"
},
@@ -57,8 +58,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#dark_metal"
},
@@ -66,8 +67,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#dark_metal"
}
@@ -75,8 +76,76 @@
},
{
"from": [
6.0,
3.0,
2.0,
3.0
],
"to": [
13.0,
4.0,
13.0
],
"faces": {
"north": {
"uv": [
0,
0,
10.0,
2.0
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
10.0,
2.0
],
"texture": "#metal"
},
"east": {
"uv": [
0,
0,
10.0,
2.0
],
"texture": "#metal"
},
"west": {
"uv": [
0,
0,
10.0,
2.0
],
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
10.0,
10.0
],
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
10.0,
10.0
],
"texture": "#metal"
}
}
},
{
"from": [
6.0,
4.0,
6.0
],
"to": [
@@ -90,7 +159,7 @@
0,
0,
4.0,
9.0
8.0
],
"texture": "#dark_metal"
},
@@ -99,7 +168,7 @@
0,
0,
4.0,
9.0
8.0
],
"texture": "#dark_metal"
},
@@ -108,7 +177,7 @@
0,
0,
4.0,
9.0
8.0
],
"texture": "#dark_metal"
},
@@ -117,7 +186,7 @@
0,
0,
4.0,
9.0
8.0
],
"texture": "#dark_metal"
},
@@ -140,6 +209,142 @@
"texture": "#dark_metal"
}
}
},
{
"from": [
2.0,
8.0,
7.0
],
"to": [
3.0,
14.0,
9.0
],
"faces": {
"north": {
"uv": [
0,
0,
1.0,
6.0
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
1.0,
6.0
],
"texture": "#metal"
},
"east": {
"uv": [
0,
0,
2.0,
6.0
],
"texture": "#metal"
},
"west": {
"uv": [
0,
0,
2.0,
6.0
],
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#metal"
}
}
},
{
"from": [
13.0,
8.0,
7.0
],
"to": [
14.0,
14.0,
9.0
],
"faces": {
"north": {
"uv": [
0,
0,
1.0,
6.0
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
1.0,
6.0
],
"texture": "#metal"
},
"east": {
"uv": [
0,
0,
2.0,
6.0
],
"texture": "#metal"
},
"west": {
"uv": [
0,
0,
2.0,
6.0
],
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#metal"
}
}
}
]
}
}
@@ -2,27 +2,28 @@
"ambientocclusion": false,
"textures": {
"dark_metal_b": "airdef:block/dark_metal_b",
"metal_b": "airdef:block/metal_b",
"particle": "airdef:block/dark_metal_b"
},
"elements": [
{
"from": [
2.0,
1.0,
0.0,
2.0
1.0
],
"to": [
14.0,
3.0,
14.0
15.0,
2.0,
15.0
],
"faces": {
"north": {
"uv": [
0,
0,
12.0,
3.0
14.0,
2.0
],
"texture": "#dark_metal_b"
},
@@ -30,8 +31,8 @@
"uv": [
0,
0,
12.0,
3.0
14.0,
2.0
],
"texture": "#dark_metal_b"
},
@@ -39,8 +40,8 @@
"uv": [
0,
0,
12.0,
3.0
14.0,
2.0
],
"texture": "#dark_metal_b"
},
@@ -48,8 +49,8 @@
"uv": [
0,
0,
12.0,
3.0
14.0,
2.0
],
"texture": "#dark_metal_b"
},
@@ -57,8 +58,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#dark_metal_b"
},
@@ -66,8 +67,8 @@
"uv": [
0,
0,
12.0,
12.0
14.0,
14.0
],
"texture": "#dark_metal_b"
}
@@ -75,8 +76,76 @@
},
{
"from": [
6.0,
3.0,
2.0,
3.0
],
"to": [
13.0,
4.0,
13.0
],
"faces": {
"north": {
"uv": [
0,
0,
10.0,
2.0
],
"texture": "#metal_b"
},
"south": {
"uv": [
0,
0,
10.0,
2.0
],
"texture": "#metal_b"
},
"east": {
"uv": [
0,
0,
10.0,
2.0
],
"texture": "#metal_b"
},
"west": {
"uv": [
0,
0,
10.0,
2.0
],
"texture": "#metal_b"
},
"up": {
"uv": [
0,
0,
10.0,
10.0
],
"texture": "#metal_b"
},
"down": {
"uv": [
0,
0,
10.0,
10.0
],
"texture": "#metal_b"
}
}
},
{
"from": [
6.0,
4.0,
6.0
],
"to": [
@@ -90,7 +159,7 @@
0,
0,
4.0,
9.0
8.0
],
"texture": "#dark_metal_b"
},
@@ -99,7 +168,7 @@
0,
0,
4.0,
9.0
8.0
],
"texture": "#dark_metal_b"
},
@@ -108,7 +177,7 @@
0,
0,
4.0,
9.0
8.0
],
"texture": "#dark_metal_b"
},
@@ -117,7 +186,7 @@
0,
0,
4.0,
9.0
8.0
],
"texture": "#dark_metal_b"
},
@@ -140,6 +209,74 @@
"texture": "#dark_metal_b"
}
}
},
{
"from": [
2.0,
8.0,
7.0
],
"to": [
3.0,
14.0,
9.0
],
"faces": {
"north": {
"uv": [
0,
0,
1.0,
6.0
],
"texture": "#metal_b"
},
"south": {
"uv": [
0,
0,
1.0,
6.0
],
"texture": "#metal_b"
},
"east": {
"uv": [
0,
0,
2.0,
6.0
],
"texture": "#metal_b"
},
"west": {
"uv": [
0,
0,
2.0,
6.0
],
"texture": "#metal_b"
},
"up": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#metal_b"
},
"down": {
"uv": [
0,
0,
1.0,
2.0
],
"texture": "#metal_b"
}
}
}
]
}
}
@@ -3,6 +3,7 @@
"textures": {
"dark_metal": "airdef:block/dark_metal",
"lamp": "airdef:block/lamp",
"metal": "airdef:block/metal",
"particle": "airdef:block/dark_metal"
},
"elements": [
@@ -74,6 +75,74 @@
}
}
},
{
"from": [
4.0,
2.0,
0.0
],
"to": [
12.0,
14.0,
12.0
],
"faces": {
"north": {
"uv": [
0,
0,
8.0,
12.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
8.0,
12.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
12.0,
12.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
12.0,
12.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
8.0,
12.0
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
8.0,
12.0
],
"texture": "#dark_metal"
}
}
},
{
"from": [
3.5,
@@ -141,6 +210,74 @@
"texture": "#lamp"
}
}
},
{
"from": [
5.0,
5.0,
14.0
],
"to": [
11.0,
11.0,
15.0
],
"faces": {
"north": {
"uv": [
0,
0,
6.0,
6.0
],
"texture": "#metal"
},
"south": {
"uv": [
0,
0,
6.0,
6.0
],
"texture": "#metal"
},
"east": {
"uv": [
0,
0,
1.0,
6.0
],
"texture": "#metal"
},
"west": {
"uv": [
0,
0,
1.0,
6.0
],
"texture": "#metal"
},
"up": {
"uv": [
0,
0,
6.0,
1.0
],
"texture": "#metal"
},
"down": {
"uv": [
0,
0,
6.0,
1.0
],
"texture": "#metal"
}
}
}
]
}
}
@@ -74,6 +74,74 @@
}
}
},
{
"from": [
4.0,
2.0,
0.0
],
"to": [
12.0,
14.0,
12.0
],
"faces": {
"north": {
"uv": [
0,
0,
8.0,
12.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
8.0,
12.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
12.0,
12.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
12.0,
12.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
8.0,
12.0
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
8.0,
12.0
],
"texture": "#dark_metal_b"
}
}
},
{
"from": [
3.5,
@@ -143,4 +211,4 @@
}
}
]
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,12 +1,11 @@
{
"ambientocclusion": false,
"textures": {
"ru_khaki_s21": "airdef:block/ru_khaki_s21",
"ru_khaki_s22": "airdef:block/ru_khaki_s22",
"pilot_olive": "airdef:block/pilot_olive",
"radar_face": "airdef:block/radar_face",
"dark_metal": "airdef:block/dark_metal",
"tube_cap": "airdef:block/tube_cap",
"particle": "airdef:block/ru_khaki_s21"
"particle": "airdef:block/pilot_olive"
},
"elements": [
{
@@ -17,7 +16,7 @@
],
"to": [
20.0,
16.0,
12.0,
22.0
],
"faces": {
@@ -26,36 +25,36 @@
0,
0,
16,
16
12.0
],
"texture": "#ru_khaki_s21"
"texture": "#pilot_olive"
},
"south": {
"uv": [
0,
0,
16,
16
12.0
],
"texture": "#ru_khaki_s21"
"texture": "#pilot_olive"
},
"east": {
"uv": [
0,
0,
16,
16
12.0
],
"texture": "#ru_khaki_s21"
"texture": "#pilot_olive"
},
"west": {
"uv": [
0,
0,
16,
16
12.0
],
"texture": "#ru_khaki_s21"
"texture": "#pilot_olive"
},
"up": {
"uv": [
@@ -64,7 +63,7 @@
16,
16
],
"texture": "#ru_khaki_s22"
"texture": "#pilot_olive"
},
"down": {
"uv": [
@@ -73,7 +72,75 @@
16,
16
],
"texture": "#ru_khaki_s22"
"texture": "#pilot_olive"
}
}
},
{
"from": [
-3.0,
12.0,
-3.0
],
"to": [
19.0,
16.0,
21.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
4.0
],
"texture": "#pilot_olive"
},
"south": {
"uv": [
0,
0,
16,
4.0
],
"texture": "#pilot_olive"
},
"east": {
"uv": [
0,
0,
16,
4.0
],
"texture": "#pilot_olive"
},
"west": {
"uv": [
0,
0,
16,
4.0
],
"texture": "#pilot_olive"
},
"up": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive"
},
"down": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive"
}
}
},
@@ -758,4 +825,4 @@
}
}
]
}
}
@@ -1,12 +1,11 @@
{
"ambientocclusion": false,
"textures": {
"ru_khaki_s21_b": "airdef:block/ru_khaki_s21_b",
"ru_khaki_s22_b": "airdef:block/ru_khaki_s22_b",
"pilot_olive_b": "airdef:block/pilot_olive_b",
"radar_face_b": "airdef:block/radar_face_b",
"dark_metal_b": "airdef:block/dark_metal_b",
"tube_cap_b": "airdef:block/tube_cap_b",
"particle": "airdef:block/ru_khaki_s21_b"
"particle": "airdef:block/pilot_olive_b"
},
"elements": [
{
@@ -17,7 +16,7 @@
],
"to": [
20.0,
16.0,
12.0,
22.0
],
"faces": {
@@ -26,36 +25,36 @@
0,
0,
16,
16
12.0
],
"texture": "#ru_khaki_s21_b"
"texture": "#pilot_olive_b"
},
"south": {
"uv": [
0,
0,
16,
16
12.0
],
"texture": "#ru_khaki_s21_b"
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
0,
0,
16,
16
12.0
],
"texture": "#ru_khaki_s21_b"
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
0,
0,
16,
16
12.0
],
"texture": "#ru_khaki_s21_b"
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
@@ -64,7 +63,7 @@
16,
16
],
"texture": "#ru_khaki_s22_b"
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
@@ -73,7 +72,75 @@
16,
16
],
"texture": "#ru_khaki_s22_b"
"texture": "#pilot_olive_b"
}
}
},
{
"from": [
-3.0,
12.0,
-3.0
],
"to": [
19.0,
16.0,
21.0
],
"faces": {
"north": {
"uv": [
0,
0,
16,
4.0
],
"texture": "#pilot_olive_b"
},
"south": {
"uv": [
0,
0,
16,
4.0
],
"texture": "#pilot_olive_b"
},
"east": {
"uv": [
0,
0,
16,
4.0
],
"texture": "#pilot_olive_b"
},
"west": {
"uv": [
0,
0,
16,
4.0
],
"texture": "#pilot_olive_b"
},
"up": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive_b"
},
"down": {
"uv": [
0,
0,
16,
16
],
"texture": "#pilot_olive_b"
}
}
},
@@ -622,4 +689,4 @@
}
}
]
}
}
@@ -0,0 +1,282 @@
{
"ambientocclusion": false,
"textures": {
"tube_cap": "airdef:block/tube_cap",
"dark_metal": "airdef:block/dark_metal",
"particle": "airdef:block/tube_cap"
},
"elements": [
{
"from": [
2.5,
0.0,
7.7
],
"to": [
13.5,
16.0,
8.25
],
"faces": {
"north": {
"uv": [
0,
0,
11.0,
16
],
"texture": "#tube_cap"
},
"south": {
"uv": [
0,
0,
11.0,
16
],
"texture": "#tube_cap"
},
"east": {
"uv": [
0,
0,
0.5499999999999998,
16
],
"texture": "#tube_cap"
},
"west": {
"uv": [
0,
0,
0.5499999999999998,
16
],
"texture": "#tube_cap"
},
"up": {
"uv": [
0,
0,
11.0,
0.5499999999999998
],
"texture": "#tube_cap"
},
"down": {
"uv": [
0,
0,
11.0,
0.5499999999999998
],
"texture": "#tube_cap"
}
}
},
{
"from": [
0.0,
2.5,
7.7
],
"to": [
2.5,
13.5,
8.25
],
"faces": {
"north": {
"uv": [
0,
0,
2.5,
11.0
],
"texture": "#tube_cap"
},
"south": {
"uv": [
0,
0,
2.5,
11.0
],
"texture": "#tube_cap"
},
"east": {
"uv": [
0,
0,
0.5499999999999998,
11.0
],
"texture": "#tube_cap"
},
"west": {
"uv": [
0,
0,
0.5499999999999998,
11.0
],
"texture": "#tube_cap"
},
"up": {
"uv": [
0,
0,
2.5,
0.5499999999999998
],
"texture": "#tube_cap"
},
"down": {
"uv": [
0,
0,
2.5,
0.5499999999999998
],
"texture": "#tube_cap"
}
}
},
{
"from": [
13.5,
2.5,
7.7
],
"to": [
16.0,
13.5,
8.25
],
"faces": {
"north": {
"uv": [
0,
0,
2.5,
11.0
],
"texture": "#tube_cap"
},
"south": {
"uv": [
0,
0,
2.5,
11.0
],
"texture": "#tube_cap"
},
"east": {
"uv": [
0,
0,
0.5499999999999998,
11.0
],
"texture": "#tube_cap"
},
"west": {
"uv": [
0,
0,
0.5499999999999998,
11.0
],
"texture": "#tube_cap"
},
"up": {
"uv": [
0,
0,
2.5,
0.5499999999999998
],
"texture": "#tube_cap"
},
"down": {
"uv": [
0,
0,
2.5,
0.5499999999999998
],
"texture": "#tube_cap"
}
}
},
{
"from": [
5.0,
5.0,
8.25
],
"to": [
11.0,
11.0,
8.3
],
"faces": {
"north": {
"uv": [
0,
0,
6.0,
6.0
],
"texture": "#dark_metal"
},
"south": {
"uv": [
0,
0,
6.0,
6.0
],
"texture": "#dark_metal"
},
"east": {
"uv": [
0,
0,
0.25,
6.0
],
"texture": "#dark_metal"
},
"west": {
"uv": [
0,
0,
0.25,
6.0
],
"texture": "#dark_metal"
},
"up": {
"uv": [
0,
0,
6.0,
0.25
],
"texture": "#dark_metal"
},
"down": {
"uv": [
0,
0,
6.0,
0.25
],
"texture": "#dark_metal"
}
}
}
]
}
@@ -0,0 +1,282 @@
{
"ambientocclusion": false,
"textures": {
"tube_cap_b": "airdef:block/tube_cap_b",
"dark_metal_b": "airdef:block/dark_metal_b",
"particle": "airdef:block/tube_cap_b"
},
"elements": [
{
"from": [
2.5,
0.0,
7.7
],
"to": [
13.5,
16.0,
8.25
],
"faces": {
"north": {
"uv": [
0,
0,
11.0,
16
],
"texture": "#tube_cap_b"
},
"south": {
"uv": [
0,
0,
11.0,
16
],
"texture": "#tube_cap_b"
},
"east": {
"uv": [
0,
0,
0.5499999999999998,
16
],
"texture": "#tube_cap_b"
},
"west": {
"uv": [
0,
0,
0.5499999999999998,
16
],
"texture": "#tube_cap_b"
},
"up": {
"uv": [
0,
0,
11.0,
0.5499999999999998
],
"texture": "#tube_cap_b"
},
"down": {
"uv": [
0,
0,
11.0,
0.5499999999999998
],
"texture": "#tube_cap_b"
}
}
},
{
"from": [
0.0,
2.5,
7.7
],
"to": [
2.5,
13.5,
8.25
],
"faces": {
"north": {
"uv": [
0,
0,
2.5,
11.0
],
"texture": "#tube_cap_b"
},
"south": {
"uv": [
0,
0,
2.5,
11.0
],
"texture": "#tube_cap_b"
},
"east": {
"uv": [
0,
0,
0.5499999999999998,
11.0
],
"texture": "#tube_cap_b"
},
"west": {
"uv": [
0,
0,
0.5499999999999998,
11.0
],
"texture": "#tube_cap_b"
},
"up": {
"uv": [
0,
0,
2.5,
0.5499999999999998
],
"texture": "#tube_cap_b"
},
"down": {
"uv": [
0,
0,
2.5,
0.5499999999999998
],
"texture": "#tube_cap_b"
}
}
},
{
"from": [
13.5,
2.5,
7.7
],
"to": [
16.0,
13.5,
8.25
],
"faces": {
"north": {
"uv": [
0,
0,
2.5,
11.0
],
"texture": "#tube_cap_b"
},
"south": {
"uv": [
0,
0,
2.5,
11.0
],
"texture": "#tube_cap_b"
},
"east": {
"uv": [
0,
0,
0.5499999999999998,
11.0
],
"texture": "#tube_cap_b"
},
"west": {
"uv": [
0,
0,
0.5499999999999998,
11.0
],
"texture": "#tube_cap_b"
},
"up": {
"uv": [
0,
0,
2.5,
0.5499999999999998
],
"texture": "#tube_cap_b"
},
"down": {
"uv": [
0,
0,
2.5,
0.5499999999999998
],
"texture": "#tube_cap_b"
}
}
},
{
"from": [
5.0,
5.0,
8.25
],
"to": [
11.0,
11.0,
8.3
],
"faces": {
"north": {
"uv": [
0,
0,
6.0,
6.0
],
"texture": "#dark_metal_b"
},
"south": {
"uv": [
0,
0,
6.0,
6.0
],
"texture": "#dark_metal_b"
},
"east": {
"uv": [
0,
0,
0.25,
6.0
],
"texture": "#dark_metal_b"
},
"west": {
"uv": [
0,
0,
0.25,
6.0
],
"texture": "#dark_metal_b"
},
"up": {
"uv": [
0,
0,
6.0,
0.25
],
"texture": "#dark_metal_b"
},
"down": {
"uv": [
0,
0,
6.0,
0.25
],
"texture": "#dark_metal_b"
}
}
}
]
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 B

@@ -0,0 +1,4 @@
{
"template": "minecraft:stone",
"item": false
}
@@ -0,0 +1,4 @@
{
"template": "minecraft:stone",
"item": false
}
@@ -0,0 +1,4 @@
{
"template": "minecraft:stone",
"item": false
}
@@ -0,0 +1,4 @@
{
"template": "minecraft:stone",
"item": false
}
@@ -0,0 +1,4 @@
{
"template": "minecraft:stone",
"item": false
}
+57
View File
@@ -0,0 +1,57 @@
//! Enemy-picture outcomes on fixed seeds (#127): what changed for the raids, measured.
//!
//! Runs the standard scenarios over a fixed seed set and prints one JSON object with the
//! completion, losses and failure reasons of every run — the before/after comparison of the
//! honest EnemyPicture is judged on these, not on "it got smarter".
//!
//! cargo run --release --example intel_bench
#[path = "sim_run/harness.rs"]
mod harness;
use harness::{big_smart, ew_adaptive, logistics, Scenario};
fn esc(s: &str) -> String {
s.chars().flat_map(|c| match c {
'"' => "\\\"".chars().collect::<Vec<_>>(),
'\\' => "\\\\".chars().collect::<Vec<_>>(),
c => vec![c],
}).collect()
}
fn run(sc: &Scenario) -> String {
let r = harness::run(sc);
format!(
"{{\"scenario\":\"{}\",\"seed\":{},\"ticks_run\":{},\"raids_ordered\":{},\"raids_ended\":{},\"all_ended\":{},\"launched\":{},\"kills\":{},\"hits\":{},\"crashes\":{},\"sams_lost\":{},\"fired\":{},\"retargets_max\":{},\"air_bytes\":{},\"switches_max\":{},\"intents\":\"{}\",\"failures\":\"{}\"}}",
esc(&r.name),
r.seed,
r.ticks_run,
r.raids_ordered,
r.raids_ended,
r.all_ended,
r.launched,
r.kills,
r.hits,
r.crashes,
r.sams_lost,
r.fired,
r.retargets_max,
r.air_bytes,
r.switches_max,
esc(&r.intents),
esc(&r.failures),
)
}
pub fn main() {
let scenarios: Vec<fn() -> Scenario> = vec![big_smart, logistics, ew_adaptive];
let seeds = [1u64, 7, 42];
let mut rows = Vec::new();
for make in &scenarios {
for &seed in &seeds {
let mut sc = make();
sc.seed = seed;
rows.push(run(&sc));
}
}
println!("[{}]", rows.join(",\n"));
}
+38 -1
View File
@@ -5,6 +5,8 @@
//! Native timings say nothing about the WASM build or the GPU; use them to compare runs of the
//! same machine.
#![allow(dead_code)]
#[path = "../../src/world_view.rs"]
mod world_view;
use airdef::sim::{Aim, Approach, DroneKind, Ground, Out, RaidOrder, Sam, SamKind, Sim};
use glam::DVec3;
use std::collections::HashMap;
@@ -126,6 +128,25 @@ pub struct Report {
pub raids_ordered: usize,
pub raids_ended: usize,
pub all_ended: bool,
/// Systems the defence lost (destroyed units at the end).
pub sams_lost: u32,
/// The most retarget route jobs waiting at once (#127).
pub retargets_max: usize,
/// The largest air section a save would have taken, in bytes (#127).
pub air_bytes: usize,
/// The aims every drone ended with, by intent: "plan:1,sead:2,react:3,replace:0".
pub intents: String,
/// The most aim switches one drone went through.
pub switches_max: u16,
}
/// The last intent every smart drone of the run was seen carrying, as `name:count`.
fn intent_counts(seen: &HashMap<u32, &'static str>) -> String {
let mut counts = std::collections::BTreeMap::new();
for name in seen.values() {
*counts.entry(*name).or_insert(0usize) += 1;
}
["plan", "sead", "react", "replace"].iter().map(|k| format!("{k}:{}", counts.get(*k).copied().unwrap_or(0))).collect::<Vec<_>>().join(",")
}
fn finite(v: DVec3) -> bool {
@@ -160,6 +181,8 @@ pub fn run(sc: &Scenario) -> Report {
let mut ended = vec![false; sc.raids.len()];
// truck id -> (last position, ticks standing while busy)
let mut standing: HashMap<u32, (DVec3, u64)> = HashMap::new();
// drone id -> the last structured intent it carried (#127).
let mut intents_seen: HashMap<u32, &'static str> = HashMap::new();
let mut out = Out::default();
for now in 1..=sc.ticks {
// Raids come in order: one is ordered once the previous one has been sent.
@@ -192,6 +215,18 @@ pub fn run(sc: &Scenario) -> Report {
pending = wanted.into_iter().map(|(x, z)| (x, z, sc.terrain.height(x, z))).collect();
}
r.ticks_run = now;
r.retargets_max = r.retargets_max.max(sim.retargets_len());
r.switches_max = sim.drones.iter().chain(sim.queue.iter().map(|(_, d)| d)).map(|d| d.aim_switches()).max().unwrap_or(0).max(r.switches_max);
for d in sim.drones.iter().chain(sim.queue.iter().map(|(_, d)| d)) {
if d.alive() && d.smart() {
intents_seen.insert(d.id, d.intent().name());
}
}
// The air section a save would take, sampled when the sky is fullest (writing it every tick
// would distort the timings the bench measures).
if sim.drones.len() > r.air_bytes {
r.air_bytes = sim.air_text().map_or(0, |t| t.len());
}
// NaN check on everything with a position.
let bad = sim.drones.iter().filter(|d| !finite(d.pos) || !finite(d.vel)).count()
+ sim.missiles.iter().filter(|m| !finite(m.pos)).count()
@@ -225,15 +260,17 @@ pub fn run(sc: &Scenario) -> Report {
}
}
r.launched = sim.launched;
r.sams_lost = sim.sams.iter().filter(|s| !s.alive()).count() as u32;
r.kills = sim.kills;
r.hits = sim.hits;
r.fired = sim.sams.iter().map(|s| s.fired).sum();
r.raids_ordered = ordered.iter().filter(|o| **o).count();
r.world = ground.world.text();
r.world = world_view::text(&ground.world);
r.crashes = sim.crashes;
r.failures = sim.tally.text();
r.raids_ended = ended.iter().filter(|o| **o).count();
r.all_ended = r.raids_ended == sc.raids.len();
r.intents = intent_counts(&intents_seen);
r.tick_total = times.iter().sum();
times.sort();
if !times.is_empty() {
+1 -1
View File
@@ -97,7 +97,7 @@ fn parse_layout(path: &str) -> Vec<Unit> {
units
}
fn main() {
pub fn main() {
let args: Vec<String> = std::env::args().skip(1).collect();
let mut name = "big-smart".to_string();
let mut i = 0;
+76 -56
View File
@@ -63,11 +63,14 @@ c3b0b6f1d9b7da434c95f2794b97b9e2c05c62ccbce9f0884df071e4ec28a468 assets/airdef/
3ecae997dc4fe1939848fc60347979c02075396a164b31dec3995a2e907a8447 assets/airdef/blockstates/patriot_trailer.json
31fecc6476129990a7d368f6d7cdb954b13e777b28d1396a68168770024112ce assets/airdef/blockstates/patriot_trailer_burnt.json
183d0b2ae9c24c94c3d83f2819e1167b5e2d134cc7889e0e3bda12aa784c7baa assets/airdef/blockstates/patriot_truck.json
421b5be0a4c80e892850f4a77d5ebb386e04153201be63241c7edc11659d03de assets/airdef/blockstates/radar_mast.json
fcc6bbe526baf5551923e2a69cdf09f506cdfd96669e1fffbea643401dd2a1de assets/airdef/blockstates/radar_mast_burnt.json
37714e19e555cc50a9f195e1a8845a28c9985c27ed38b577c0813f4629b66fcb assets/airdef/blockstates/radar_panel.json
95fe14b9d3e30597f5505aa93f31c3357cebea6117596bd9f5a5bc840ab22415 assets/airdef/blockstates/radar_trailer.json
a95a1b8731d6bedda7d8b352ff3c448ea8be691b0ead01f14acab39234590c45 assets/airdef/blockstates/radar_truck.json
332e6f39c40063ca690064e13a1a256ef215fc2bb96985b842d9dda58abee2eb assets/airdef/blockstates/radar_truck_burnt.json
67b93302bea867248b6fa0109a4b5af2065e5c857d4a5c7e088bc9849fe624de assets/airdef/blockstates/reentry.json
ac9ff6b121adfc64ff60110a4e49bd5ec8e6b5ad57d45ee348b4ef1af7361264 assets/airdef/blockstates/rm48u.json
7f3e952f5de83880549012945827f8469883355b0a3dd966e7f03c44aee532ab assets/airdef/blockstates/s400_chassis.json
411d0a0ac102b21016bf48d30482e073a7e8054c2775d8fd5a7c91364a2cb1f7 assets/airdef/blockstates/s400_chassis_burnt.json
3ffc2edef1362f318d6c087a20cd730feda6f35f7381942cfc8012f06f4dc174 assets/airdef/blockstates/s400_tubes.json
@@ -87,6 +90,8 @@ e766e18158d00f0480f6dfe32dfe142890b8d452bc493b7474fda0984cc2dd4c assets/airdef/
ff125150e206ada5a7fb47394e809039d338c22a843207a32352e9ee59e278a3 assets/airdef/blockstates/tor_chassis_burnt.json
04a5fb931f419086995791c1defd9486b36b3c725581bf5a10191a2c71c69984 assets/airdef/blockstates/tor_turret.json
fdcbe36a0f4968005e8c6588f2fa5d8196c55da3183cf89760ea221a5c4cb431 assets/airdef/blockstates/tor_turret_burnt.json
923340f2233c363a880fffeb40dba04038f26ff42b072f28418e0a6ab757aac5 assets/airdef/blockstates/tpk_cap.json
f3e430750f5cb60f44c2a97687d7cc1ac58232b27274a82758c23861d704662a assets/airdef/blockstates/tpk_cap_burnt.json
cf7c26abeb1d8f7d84106bd83b84bf541a3d11369b7745a77802b7e51dcdf447 assets/airdef/blockstates/tracer.json
8b547ccbc890fa53b613cdb2cf55ceaa5833348479b0863651c6df01a9f778b3 assets/airdef/blockstates/tzm_truck.json
11fca31a88e658c819954fbb86b53d7709b66b971af8747a5edda24be34e5dbb assets/airdef/blockstates/tzm_truck_burnt.json
@@ -131,100 +136,105 @@ b4d98a938486d49db28c6c7a608ca3b6ab0c9c3eac266ecf12c7dd931cc28f93 assets/airdef/
489799dcb5b441e9d4be8bfb3d73a6ebd5fdf2b5ee614b62f38b85bb2fbfad75 assets/airdef/items/launch_zircon.json
6b6da5887aa8d9bc987b2c181c243bc2afdd5846a869818f699b59204e559929 assets/airdef/items/mover.json
177f7535e4c52ed975d6f737c2b2acb7741b7a928955c8899aced85211443bbf assets/airdef/items/remover.json
9c54b89d2840841494bdfb2161c038385b23e41a42a87a24e95d485a1a541a82 assets/airdef/lang/en_us.json
9c54b89d2840841494bdfb2161c038385b23e41a42a87a24e95d485a1a541a82 assets/airdef/lang/ru_ru.json
cede33ba58f61891a8afe42e1f4311cb293ca93f4d7eb3a57636caff17317a4d assets/airdef/lang/en_us.json
cede33ba58f61891a8afe42e1f4311cb293ca93f4d7eb3a57636caff17317a4d assets/airdef/lang/ru_ru.json
b9b5b5bec33a77e944552c225ee2f526ab9820fa8fca4b3ccf311f2a325925ee assets/airdef/models/block/amraam_missile.json
c54e6b24ab69e9d9a2dbbbc63fe2ac60fa37735bf644500ddd5c3de0b91908cf assets/airdef/models/block/barge.json
a4198ff647de5866919f9b82a3d53e6486fc56cc9f175f7907951d063a6f4526 assets/airdef/models/block/beam.json
050bc585d82f48b39fee175ba795fafb642fc2658c932901549d8907e5d63401 assets/airdef/models/block/buk_chassis.json
384ef97ea938470c82e68ab9659b9cb67cb69494fe3b9eb14357107bc6ad416b assets/airdef/models/block/buk_chassis_burnt.json
e2b031f4edbfd8395ff04311bca5bb3c4a2fd5cd7022d1070c8c7f67a6aa7177 assets/airdef/models/block/buk_rails.json
a76b58dd0c282353b9101beb48774d5619369303e0665fc821458a47cd3d0402 assets/airdef/models/block/buk_rails_burnt.json
bdbb639071f3ff18fd624f3179aeb5dcd1216828b599e976617c13e5c77d115b assets/airdef/models/block/buk_turret.json
7f1248fe849972d51a37c4162d92991b5567487b5415e2e9ea2cf43644bb500b assets/airdef/models/block/buk_turret_burnt.json
87c5b37677b74fc0eb83db9d946f63a4b05651734e5a6c00f49c2bd30acaade2 assets/airdef/models/block/buk_chassis.json
e06845ed1a8c3b6bc737ae0415c8170c24fbbf30ee6c03d92e69558047647018 assets/airdef/models/block/buk_chassis_burnt.json
e51314abb51660f2e06d896084802ae913c3a233a05f5531b9d2fb83f1066f7c assets/airdef/models/block/buk_rails.json
b305b7fe737f9a303bd60dacff4e71468835e63b09fc6af5e63ecb248e390572 assets/airdef/models/block/buk_rails_burnt.json
3a0f03c100dd8811349798e3baa5cdab53be12381dd1faabbe5375cfdb1fe332 assets/airdef/models/block/buk_turret.json
d64884c030716bc212bbfa04b2308714f8f0a116a14e0249847859a0cc96fa3d assets/airdef/models/block/buk_turret_burnt.json
684edfac71d15f328b92aee2f2cc508532f6654d5a664ac78c13b6868c3307ba assets/airdef/models/block/debris.json
aef93931af7ed7bf71eca89070adaf52af9e0d8894d3d4e36c926b219e196e02 assets/airdef/models/block/depot.json
107aec61d1dcbbfc6ec9203cf8590c23cde3cb22e8debc121b6ea30d675e6401 assets/airdef/models/block/depot_burnt.json
89ea90f53a06814d71cec4d8e89a43d7dbbc4536a8104d099b743332cabafedd assets/airdef/models/block/ew_truck.json
b7cd8f04aaf8a6c5b7021a59dc7f6c60e29b1159237ba666d7eeefb91254f348 assets/airdef/models/block/ew_truck_burnt.json
de1e494d4b9543ffb72f6b351830d2821ba3e344baaf0f7d365f771fa9d5ba24 assets/airdef/models/block/depot.json
b0f94e748ecc44fffa6711b1affa8e2a4ccf95e6fb101c8577e0f118f31133c2 assets/airdef/models/block/depot_burnt.json
6e99fc5296a9251bbe04379da7122faee34df156d77f4888daa27b9f9d54c6e4 assets/airdef/models/block/ew_truck.json
4e270f0092d3c10acaaec5f3824f43c0e16c1191b837187af10aa3b0b5791a9f assets/airdef/models/block/ew_truck_burnt.json
c00df220e46a265c5a33e68df1cf407dc1fd25bb70978b6b8d850d7826044f3c assets/airdef/models/block/fireball.json
fd5ca8c85d054580e6f95cb88bfed6216c9b41ddab9efec2eb4a642ad408c17c assets/airdef/models/block/flame.json
3962ad6a9bfd88ed4638dd72d27ddbd0933583e7f0d40b808ddabfd6e3a35399 assets/airdef/models/block/flare.json
6bf4a388b9a38a5359053be38cf09f1c86d0ea47d61e5de0016b2b1c7f7dbb4a assets/airdef/models/block/flash.json
9fa54aaabfc0dd1b6af4fdd1fd4ac9a4248c4837801a7d74e441627f565a18fa assets/airdef/models/block/gepard_dish.json
993b426346250e248abea70a461a7e9343d264585997adee252d8f803d635acd assets/airdef/models/block/gepard_guns.json
9f5b572110c02fbae42a1aff8db716094d198b209d19dfc2e6a72430378fc179 assets/airdef/models/block/gepard_guns_burnt.json
288029fc93a84ee5d68605d061bde9fdb31b759a4a17766bb8df008beb9c2064 assets/airdef/models/block/gepard_hull.json
743dba3635ae9683e744c1691315a104e48e10011cfbe6e74565eecd6ce7dfcb assets/airdef/models/block/gepard_hull_burnt.json
38ae7a16ba13e5ac0cff7f8f1856e24b512f4e68bff7b71297b3d2838333fc2a assets/airdef/models/block/gepard_turret.json
cf464948fd36c74cf6f49b10f4f2e0e4b9e52b9d8324c27302e8e1c2ae8ae73f assets/airdef/models/block/gepard_turret_burnt.json
c8146e2999b4b94633abd1fbafdb39fca8896e9df92aa37c78544ee594337218 assets/airdef/models/block/gepard_guns.json
e8a9c326e2630d7484e1a11ce8a30d2a0005dc4c847c62b5e425904d6ac4fcf1 assets/airdef/models/block/gepard_guns_burnt.json
48a3496b78b37dda0a6eff1ed610458824949dd11c56626dffaf6158f8c1c7ae assets/airdef/models/block/gepard_hull.json
eec91700830aaea1c7d80a4af3ca44b99756bba18ca634e0107004f4ed59ae06 assets/airdef/models/block/gepard_hull_burnt.json
e666f027e7cd54c6c9596d896931db7c51a5b74564e7038f9bceb6824c6c29dc assets/airdef/models/block/gepard_turret.json
da2509d47a048c59c81430a83fa71ac0a0d312a2ec617ed1d3175b5ceb75ccd1 assets/airdef/models/block/gepard_turret_burnt.json
d43f9cda780b1821a6e778555a1be5bd112a1d9655ff96d35acebec61cf11e0b assets/airdef/models/block/geran3.json
83cf0a42e59f6aee1039925f849398960334f2545558409e7ccd7173ac841d73 assets/airdef/models/block/geran3_flame.json
ac93e872743844465f0688162dddd7433352e8710612dd391a1e92b7f36e6b0d assets/airdef/models/block/gerbera.json
8c273c2e02dd1884012f5597a6ad2022a0cfcf56c9c5b23043729d3c34635783 assets/airdef/models/block/irist_chassis.json
417c68e386d715da987c2d2e9fe86d25dcf0d923546b602d5f01c1eba1d25543 assets/airdef/models/block/irist_chassis_burnt.json
3ed12c12f9c1490ef08585cd4a55632cd94528e9bbde1e993310f1e9ca57c534 assets/airdef/models/block/irist_chassis.json
122e7dbb3cba0b8e249c8a06251d3ef83dcbe1880d540b0d4c2430910314f34d assets/airdef/models/block/irist_chassis_burnt.json
db7b914b2d027b8ebde485b940951244e4bc4cb614eb2eefc49ccf0b26c98bdd assets/airdef/models/block/irist_missile.json
89453602195bc437ecb70885ad4475bc04ee300eff377682321bc3cd1113e9d7 assets/airdef/models/block/irist_tubes.json
c8cb7d80202b72070e955015d4abeffb33586c9fa94a3ca29311ae68cfd7ca9a assets/airdef/models/block/irist_tubes_burnt.json
e6cb3f578b875d3683d2a027f1ac34226b56c4db410fecc6479e2683485b8c3e assets/airdef/models/block/irist_tubes.json
449284669a58d71ae2de7e68cd7cf18ae21fec70ceb3124cd24fb4a09fc49909 assets/airdef/models/block/irist_tubes_burnt.json
be87037b84cd45b2c53d7fde6653f51769e782eea1b8586383afcfababf19ab6 assets/airdef/models/block/iskander.json
98d488ca797fb3d0193957b8a93a82f48376a89f8e091032e6365d1845016a90 assets/airdef/models/block/kalibr.json
be9eb1389e169a76732f16e604499260b147b524b4c929d2a4e77b580a032fb7 assets/airdef/models/block/kh101.json
20deb68dbba6eb64b7c51685497110ef7d1d3bf0aa7e7167c558e0a8e842e759 assets/airdef/models/block/kh101.json
ea7c9af888f1285502b2ca51114f226573311be6fb90b8d449b9f75cfbb6b885 assets/airdef/models/block/kh22.json
7b73015e33d85d4cef31660ef874ba8dcd6e07ae3a95416d0ead1d325bd0cb6c assets/airdef/models/block/kinzhal.json
911e55de28058e1723a61d15de80676789e57ab15bfc09fd75757cc85095fbcb assets/airdef/models/block/lancet.json
69135e90a1a7fb21d9f47b1854c5a3648e296136c2375acd9db5a48b0ad40887 assets/airdef/models/block/lancet.json
15c9884ce51311cf4b9b9d106e142e33d72c5ba18dc9236c5b51da01232f8e44 assets/airdef/models/block/launch_ramp.json
159fa5e3b6a096a1872dec2a550bfa30575d57519654a860607e20dab8f35f53 assets/airdef/models/block/launcher_truck.json
2069198ba24a932816f504fb52f53dc4bc740cacaf45637698a17d9175da851c assets/airdef/models/block/m48n6.json
61968f4d63adb6dfebd5770ce5225f4cf5610a7d7ef863c4665875e82abb4f25 assets/airdef/models/block/m57e6.json
238ed59a5dfa261272c0a4dabbda3ee62d2c1c7b9829cced644bf8b2322d4bfc assets/airdef/models/block/m77n6.json
e8786fdbf6feb21f4819015c7faaf87983f4a7ed88c6f7917bd49d1b14eb9140 assets/airdef/models/block/nasams_launcher.json
574e069129ff20e6137b469740cb279e16e70beeafd1e933c22cd7dca583d74d assets/airdef/models/block/nasams_launcher_burnt.json
56a0a41e54b5056689525909179651dd5ec0fe551c06bd2bd2b1edb63c369aec assets/airdef/models/block/nasams_trailer.json
79b26bc489f644afbff7a9f616481b81034fb13a0590e88ca1753601eca4f3ea assets/airdef/models/block/nasams_trailer_burnt.json
266565d9ed8dc836c46028c8b8bdc83c9725db587552bf8848cd9059f3917ed4 assets/airdef/models/block/nasams_launcher.json
94c8beaf3226c86d5ad018a31846286b451eaa96073e07be4465c9de3583ef61 assets/airdef/models/block/nasams_launcher_burnt.json
99d3a530ca47536443db0e2c8a8f9236d68f67b6c78a5313c44dd80fb6edbde0 assets/airdef/models/block/nasams_trailer.json
ab0d875ad069ccd241f3c75fd32ecbe3507cfe740aa072a3a75955c489629ec6 assets/airdef/models/block/nasams_trailer_burnt.json
ce9f0dc61bd07cfcb3be5cadf12df0d2ef1b3167aa2260bc4b42414dc3825b58 assets/airdef/models/block/p1sun.json
b5346ab109ffb8c259592574b091a47bd396de34b0fe96e684b672316cee6b86 assets/airdef/models/block/p1sun_launcher.json
4457a527977ad5c7d381991ca1c9d304cac0b7074f632a04328e836bfd83f784 assets/airdef/models/block/p1sun_launcher_burnt.json
2e11e64942baaf057ccc60f42dc629f7519eb3892198c1906c22fcfa95584e7b assets/airdef/models/block/pac3.json
ba90d89595c3c5d6d5a30f1041540f50504676bc64df5cf34038f8682307bd3e assets/airdef/models/block/pantsir_dish.json
622c6f537f6adb99b1a536e38eb0a5d30c05c62f671997365ff0b2e9fa9e6562 assets/airdef/models/block/pantsir_pack.json
5413c0a546ee6b82dcf3e782d6cdab4e7080642b71bbb08a4b800a9105f39216 assets/airdef/models/block/pantsir_pack_burnt.json
52aacf44022a6826bd88fb161bce81966033de89f67b9d505c1b649bcf294eb0 assets/airdef/models/block/pantsir_truck.json
53e0a5c2bec25e3a52eb52bb098c9aa186f737fff7d6c5b2ccf927c313416e1e assets/airdef/models/block/pantsir_truck_burnt.json
84857ebb50b8e98796e3907d8ce4eeb8427c29de9f81aec7a8bd8d9ba4ca516e assets/airdef/models/block/pantsir_turret.json
fc3555a87f290805ad723607f034d90645799cd8d9ef3ba42fedee2a50248059 assets/airdef/models/block/pantsir_turret_burnt.json
9a461291c90e18c50f3a82afe7f17bc8a0a299b9f2b925c244580087fc3b5fa5 assets/airdef/models/block/pantsir_pack.json
79af2971ac88a93bbc42c0e193f61e585f6ae5330153f4b40b7720c5ce8e4cd0 assets/airdef/models/block/pantsir_pack_burnt.json
ef73f453ea0abcd97121c845207efcf2438d47991d49bac1cae66acc9a416419 assets/airdef/models/block/pantsir_truck.json
1d3a00601801268636165e8fea79f9c9d141e1434f0268e2f65ef67ecddd4447 assets/airdef/models/block/pantsir_truck_burnt.json
d01efdcfafa92243e745aea7870269c07a0224c9010010e2dbed720ced1662c5 assets/airdef/models/block/pantsir_turret.json
0036037578cf2df9f565acd8ac3553af9038ebafb5b9a4e6d8fd0d225b39149c assets/airdef/models/block/pantsir_turret_burnt.json
33884253bc3ab463d15a7fe952187b1f9fb3b78632e825e1fabc85ca5335b543 assets/airdef/models/block/patriot_launcher.json
3fed073655020b72dd515dca7eb362f642af50251b473012429a5ca946426f8d assets/airdef/models/block/patriot_launcher_burnt.json
2a8ca10c933e236270810ce9de40c83dfd8016b0f0d32413433e3a5f8622329f assets/airdef/models/block/patriot_radar.json
eb9a8af98374220657fa722a281bc18f6d884d51c5869975d43eeabcb171677b assets/airdef/models/block/patriot_trailer.json
428fbe50bea9dbca55bc4933b15ccecf57164dc915e661ec9ae610151810a50a assets/airdef/models/block/patriot_trailer_burnt.json
4c3dcfe38527de677cc1d56f6fdf17980604b93ce24f4337b3f825a2f446620b assets/airdef/models/block/patriot_truck.json
548bc63e46d96e5110598e39269851c48f750164981a433f75971b0229c268df assets/airdef/models/block/patriot_trailer.json
190726b64bef4baadb0bc2a00147069685ef148100c8935402e09c3bef66e65b assets/airdef/models/block/patriot_trailer_burnt.json
6f027b020e4066f673c376e289cc627846a084e5733d62744fe78ab23013fb08 assets/airdef/models/block/patriot_truck.json
8070d24b511ac733d73f5961762e6f5995379814f33f54c56c1a45d1dd7ff28a assets/airdef/models/block/radar_mast.json
7343f6085138f974d581706cc135e582040a46069c215e95ba14ad31dc1a8d63 assets/airdef/models/block/radar_mast_burnt.json
e5733ece9b976998c9c6a6c968b17cada868b62d9e2a7bc67e1272e333e35399 assets/airdef/models/block/radar_panel.json
b0ae344fbad3b982e7821cd1b26f9922e2a5713b38107521ddc5a5b2abd9e39c assets/airdef/models/block/radar_trailer.json
088f42bb17f4d6099c16adf6cc0426b6d04ff9a43abdf125476a3571e924fcbd assets/airdef/models/block/radar_truck.json
4cd60dfb1e598efbd127894b0ad1b1737569dfc0fc5c9b193034f9125daa9c15 assets/airdef/models/block/radar_truck_burnt.json
5545094620c27fae6b3d97a71f3d68ee8e0b49804a1dcd61b79ca847277e3b61 assets/airdef/models/block/radar_truck.json
5c756abfb412b31076cd84d8735ad4e41ca26c8d5896e3795aaddb976aefbd1c assets/airdef/models/block/radar_truck_burnt.json
f102765390762d45954b26405b6acdde845df7f0a319bac53d25508e768957b5 assets/airdef/models/block/reentry.json
0a27047ed66a18b513c5113e4b4ba1d8667ac75d36f661e58415a9d6870c0bc9 assets/airdef/models/block/s400_chassis.json
b86ccc0a31dc63239b598542070173ebbc6d354b3d8dec880c62ea192d6ea9f7 assets/airdef/models/block/s400_chassis_burnt.json
0107a6689048c7267ea1c68713593026fa495cb33443a6b1aab815a17602fe81 assets/airdef/models/block/s400_tubes.json
6e4a35843d29bba30b9969af7ed9a60ad05ea4e4b9fde0507ea6ba6dcb9d7dd7 assets/airdef/models/block/s400_tubes_burnt.json
971c11e58eafa17ad798f6d27d91a9ee0531f33692eb657d31f2d83e8cee7e39 assets/airdef/models/block/rm48u.json
a6bb637011c176edae474ae7b5d6e3b5af0d2a448845e3f95b026f789e21560f assets/airdef/models/block/s400_chassis.json
192076b361a57ee26a1dd449717f30f50b612ee6c88d4dc1fb9dc6aef3f3b829 assets/airdef/models/block/s400_chassis_burnt.json
44bf27184842d0e3c86bed035a7090add0a79f6b5bdea7a37e6ddaaae728d39a assets/airdef/models/block/s400_tubes.json
973e02b2058c0b3d59c156f2ac94fbba4ac90a97736e8a4cc9be177b5e0f19a9 assets/airdef/models/block/s400_tubes_burnt.json
088f42bb17f4d6099c16adf6cc0426b6d04ff9a43abdf125476a3571e924fcbd assets/airdef/models/block/s500_chassis.json
3e35ed19ea22c8309ac7c0ccc9c12e31b2387de97c6b72ba519bae34f681c58c assets/airdef/models/block/s500_chassis_burnt.json
6ce00881e2a5107874e82e94a243fcd95c3eb6e9a24e8839c11227c8e330485f assets/airdef/models/block/s500_tubes.json
88109407ec749d6f45a4a38a9a43fd1594ac6190d7f08433b07da572c040458d assets/airdef/models/block/s500_tubes_burnt.json
536928e90a907c50b078a488bad49061f79aafe12479f58a2b2ce79aaad5adda assets/airdef/models/block/searchlight.json
0e3cbae5029377886325aedc43705d9975cb1dc889a37613b92a97bdf36b4db7 assets/airdef/models/block/searchlight_burnt.json
2d790e8845598e8cf7ae577492632ef52e075d590011e66fa8ab686096cda313 assets/airdef/models/block/searchlight_head.json
f0f9ec6cefc0750e4d6cb330c21df8c2bcf02b1b7408f90f40ebb35a572a13cb assets/airdef/models/block/searchlight_head_burnt.json
b2e28d73f50b238f6bc7d6dae560695e70ae8b843f6853f9e468bf8d2b371e6c assets/airdef/models/block/shahed.json
8c6bc46647f3df32febd96fccdba894e4c986b717b006e3c3e5607a73f0f252f assets/airdef/models/block/s500_tubes.json
135d34c4059ea7aca794cce201ef27c3c17cdb21ea27205634cea95bc8d16515 assets/airdef/models/block/s500_tubes_burnt.json
3d61559d5bde298d6dc8987122c68edc3b02bd0d1afed1d9458bd7c3315fb0fe assets/airdef/models/block/searchlight.json
6391c155f45656f63ac579bd1ff0d3512c54830a03561b8dd04e5e63ed751cf4 assets/airdef/models/block/searchlight_burnt.json
357165a1a1ad382257e68768bf1b4158294e0e080eab9a9570ed6bd824e7f3aa assets/airdef/models/block/searchlight_head.json
1ca6eff892a0101bcd950323d2f9c68cc81d6c714086a44555ee49441797fbc3 assets/airdef/models/block/searchlight_head_burnt.json
60c44090d52fd08f230b3f37b58e888824e680b5411dd4c3c6220da6ff3d15d8 assets/airdef/models/block/shahed.json
d5b9ed76b1744d0c93a809b6a4c16bc3dfa7ff4784e3cb9968aa36b12fc30484 assets/airdef/models/block/shahed_prop.json
465e6aa2a8ac3c563b1e546fc844a0520fc89f3ce528d49f193aa6c21e19308f assets/airdef/models/block/target.json
69c5c103c228abe6162f2e1252139689b768ff8dd3f835f8f79ce7d324c3f124 assets/airdef/models/block/tor_chassis.json
81e66314bfcd4786950ab4c23c6ede79ff9b30687b44f23e2b7b9be233fe380f assets/airdef/models/block/tor_chassis_burnt.json
b2d2f856a4004853cb799785c0a586d605c623759d5a099dc70e19ba6a67b100 assets/airdef/models/block/tor_turret.json
e95be4a89de1384038df47861705b934b0091f61f7b135c9ea6933fe2197f31f assets/airdef/models/block/tor_turret_burnt.json
8f4d29f5cff68b74880d2120a0f183a35018d36576330bb33de3789cf769683a assets/airdef/models/block/tor_chassis.json
cacaa7265489f1083f7de351515a7d08eac5d2b072cf58b32ee51840473ab44e assets/airdef/models/block/tor_chassis_burnt.json
d130179a7717f1bff9f045a3e0b93788eff17737c7c1c9c3b5b287d811eb6fad assets/airdef/models/block/tor_turret.json
a98d2a545b4bdea5cff1c5826d55dc8c3fd341ecebeb8b00ee2e1e1b0739b2cc assets/airdef/models/block/tor_turret_burnt.json
a6785198c98f5b2f20acc26ddeca3b5432e6b521b68541ea65ca2592c3cae4a1 assets/airdef/models/block/tpk_cap.json
0391ce9eeac9aa0cfcc05b31b0bd5594e10a5df2dc46c355b0b95a8ea8234ff5 assets/airdef/models/block/tpk_cap_burnt.json
b2380510f56dc60e914919cb6e20b82e3613a9d62b08a1c81740f960569c3425 assets/airdef/models/block/tracer.json
447d237b290255f01c7ce51047df3de1b9261cb75cfeb83ab190f6abe914747d assets/airdef/models/block/tzm_truck.json
1954ece9e339d89a6ce63b78d255637011b3661572fdfe051ea4814a891746ce assets/airdef/models/block/tzm_truck_burnt.json
753c46e821b4fce9fd9240de2ec627a27688740a4c31c9eff24593034ffa33e7 assets/airdef/models/block/tzm_truck.json
fa29c0224a5a7ad2e3252cde099b17c6c8241ede7cf0e52766734672843a6432 assets/airdef/models/block/tzm_truck_burnt.json
b85d09a73a1c251bbc76945aa8f99b5e7e606ed41e1d120f811a435f441b1e96 assets/airdef/models/block/zircon.json
8360c341dbe0aac6c485bf0d2c9ace49378173f1749f5b52793a79b98697685b assets/airdef/models/item/cam_geran3.json
5b35d42715fa9c4afe8d0bccf5060380a8b5216edc9509ba0d859e8e953232d7 assets/airdef/models/item/cam_gerbera.json
@@ -346,6 +356,10 @@ dd8c9056df254fe788a6848c96af4e56c5951f08717b25ebaa8815d1fb823751 assets/airdef/
311932fa43f0b513342e8f3746208bd845b936f883f6f5c8d453fd4ef6d315dc assets/airdef/textures/block/nato_tan.png
6a1289cfba0b17732cedfadceb6522b0b9f847f754dd56975716b3e2e21e777a assets/airdef/textures/block/nose_dark.png
a8c0d707e86dedb7591b7e89f07ffd2df85ab0763e903a4c4c9ea17c97c4baee assets/airdef/textures/block/nozzle.png
85c25585f0701d719a4750f77c1eb1d63fcb469741caa27aeb5b7a04fdff7279 assets/airdef/textures/block/pilot_nato.png
e2a967933fe524abf37135e61b1aede6443a8a44d7cbe0438a0c4b4e49d6721f assets/airdef/textures/block/pilot_nato_b.png
c912a25df82af9bdfb864e7e7a018accdd048fd729a672fa4b088c663555beaf assets/airdef/textures/block/pilot_olive.png
e2a967933fe524abf37135e61b1aede6443a8a44d7cbe0438a0c4b4e49d6721f assets/airdef/textures/block/pilot_olive_b.png
3f908df37b1456884d840e346f2da60ccce5b61bd226317de9ca24430bd59a8c assets/airdef/textures/block/prop.png
98442b32c81dd7523c8d38bc6ae9810d8e0295474c814533b7fbde33f4910e3b assets/airdef/textures/block/radar_big.png
5dff7780ae2f934bc05bb58742f1965b7cf06ad28459d6dd63b574a0a327f949 assets/airdef/textures/block/radar_face.png
@@ -502,11 +516,14 @@ cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/ho
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/patriot_trailer.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/patriot_trailer_burnt.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/patriot_truck.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/radar_mast.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/radar_mast_burnt.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/radar_panel.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/radar_trailer.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/radar_truck.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/radar_truck_burnt.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/reentry.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/rm48u.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/s400_chassis.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/s400_chassis_burnt.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/s400_tubes.json
@@ -526,6 +543,8 @@ cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/ho
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/tor_chassis_burnt.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/tor_turret.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/tor_turret_burnt.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/tpk_cap.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/tpk_cap_burnt.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/tracer.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/tzm_truck.json
cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/horizon/block/tzm_truck_burnt.json
@@ -570,3 +589,4 @@ cc0877f40434365b45b03429222926aa0cf135e504017311be53263fd27c5f8f data/airdef/ho
2a3912a7c9d5bb8025b1ac16a1a1d6b5eff0360bb3184e810d319e498255bf97 data/airdef/horizon/item/launch_zircon.json
2a3912a7c9d5bb8025b1ac16a1a1d6b5eff0360bb3184e810d319e498255bf97 data/airdef/horizon/item/mover.json
2a3912a7c9d5bb8025b1ac16a1a1d6b5eff0360bb3184e810d319e498255bf97 data/airdef/horizon/item/remover.json
5e0c0090b5aaded5b86b245cb30bcd0cbaa82f632a362d490d79bcf2794e25fd src/sim/generated_bounds.rs
+15
View File
@@ -0,0 +1,15 @@
# Authored source assets
Place artist-authored overrides under `assets/airdef/` in this directory, preserving the runtime-relative path.
For example, an authored icon at `source-assets/assets/airdef/textures/item/deploy_gepard.png` replaces the
procedural icon at the generated runtime path while the source copy remains untouched. The asset generator
copies this tree into its temporary staging tree, validates the merged runtime assets, then installs them using
the generated manifest. Do not edit generated files under `airdef-mod/assets/` directly; an untracked or
hand-edited output is treated as a conflict and left untouched.
This directory is intentionally kept separate from runtime and generated output. The initial art pilots are
S-400 chassis/canisters, Gepard hull/turret and Shahed, including burnt variants for the ground vehicles.
The JSON is editable directly. `python tools/pilot_models.py` is an optional authoring helper that overwrites
only those named pilot JSONs; the normal regeneration never invokes it. After editing, run
`python tools/gen_models.py` to validate and install the authored models. `generated_bounds.rs` is derived
from the final staged geometry, including overrides and element rotation, for chassis navigation.
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More