mirror of
https://github.com/XevianLight/Aphelion.git
synced 2026-05-10 17:40:56 +01:00
More partition and station backend
This commit is contained in:
3
doc/Aphelion/.obsidian/app.json
vendored
Normal file
3
doc/Aphelion/.obsidian/app.json
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"alwaysUpdateLinks": true
|
||||
}
|
||||
1
doc/Aphelion/.obsidian/appearance.json
vendored
Normal file
1
doc/Aphelion/.obsidian/appearance.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
33
doc/Aphelion/.obsidian/core-plugins.json
vendored
Normal file
33
doc/Aphelion/.obsidian/core-plugins.json
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"file-explorer": true,
|
||||
"global-search": true,
|
||||
"switcher": true,
|
||||
"graph": true,
|
||||
"backlink": true,
|
||||
"canvas": true,
|
||||
"outgoing-link": true,
|
||||
"tag-pane": true,
|
||||
"footnotes": false,
|
||||
"properties": true,
|
||||
"page-preview": true,
|
||||
"daily-notes": true,
|
||||
"templates": true,
|
||||
"note-composer": true,
|
||||
"command-palette": true,
|
||||
"slash-command": false,
|
||||
"editor-status": true,
|
||||
"bookmarks": true,
|
||||
"markdown-importer": false,
|
||||
"zk-prefixer": false,
|
||||
"random-note": false,
|
||||
"outline": true,
|
||||
"word-count": true,
|
||||
"slides": false,
|
||||
"audio-recorder": false,
|
||||
"workspaces": false,
|
||||
"file-recovery": true,
|
||||
"publish": false,
|
||||
"sync": true,
|
||||
"bases": true,
|
||||
"webviewer": false
|
||||
}
|
||||
22
doc/Aphelion/.obsidian/graph.json
vendored
Normal file
22
doc/Aphelion/.obsidian/graph.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"collapse-filter": true,
|
||||
"search": "",
|
||||
"showTags": false,
|
||||
"showAttachments": false,
|
||||
"hideUnresolved": false,
|
||||
"showOrphans": true,
|
||||
"collapse-color-groups": true,
|
||||
"colorGroups": [],
|
||||
"collapse-display": true,
|
||||
"showArrow": false,
|
||||
"textFadeMultiplier": 0,
|
||||
"nodeSizeMultiplier": 1,
|
||||
"lineSizeMultiplier": 1,
|
||||
"collapse-forces": true,
|
||||
"centerStrength": 0.518713248970312,
|
||||
"repelStrength": 10,
|
||||
"linkStrength": 1,
|
||||
"linkDistance": 250,
|
||||
"scale": 1.0000000000000004,
|
||||
"close": false
|
||||
}
|
||||
166
doc/Aphelion/.obsidian/workspace-mobile.json
vendored
Normal file
166
doc/Aphelion/.obsidian/workspace-mobile.json
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
{
|
||||
"main": {
|
||||
"id": "e4858043d22b0b8f",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "532e7f40f2f6d233",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "dd3aa3882d71522e",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "empty",
|
||||
"state": {},
|
||||
"icon": "lucide-file",
|
||||
"title": "New tab"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
},
|
||||
"left": {
|
||||
"id": "ef492a321aaff5d7",
|
||||
"type": "mobile-drawer",
|
||||
"children": [
|
||||
{
|
||||
"id": "8ac904c1d115ad34",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "file-explorer",
|
||||
"state": {
|
||||
"sortOrder": "alphabetical",
|
||||
"autoReveal": false
|
||||
},
|
||||
"icon": "lucide-folder-closed",
|
||||
"title": "Files"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b5703ef3f8bb0a5b",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "search",
|
||||
"state": {
|
||||
"query": "",
|
||||
"matchingCase": false,
|
||||
"explainSearch": false,
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical"
|
||||
},
|
||||
"icon": "lucide-search",
|
||||
"title": "Search"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "0263f9cd9603ec29",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "tag",
|
||||
"state": {
|
||||
"sortOrder": "frequency",
|
||||
"useHierarchy": true,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-tags",
|
||||
"title": "Tags"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "32aff3798d7e7786",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "all-properties",
|
||||
"state": {
|
||||
"sortOrder": "frequency",
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-archive",
|
||||
"title": "All properties"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "173117389aed98b1",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "bookmarks",
|
||||
"state": {},
|
||||
"icon": "lucide-bookmark",
|
||||
"title": "Bookmarks"
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 0
|
||||
},
|
||||
"right": {
|
||||
"id": "8a74ec400de5884c",
|
||||
"type": "mobile-drawer",
|
||||
"children": [
|
||||
{
|
||||
"id": "79d5d838a514d7e0",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical",
|
||||
"showSearch": false,
|
||||
"searchQuery": "",
|
||||
"backlinkCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
},
|
||||
"icon": "links-coming-in",
|
||||
"title": "Backlinks"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ef29c5a2c8cb51ca",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "outgoing-link",
|
||||
"state": {
|
||||
"linksCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
},
|
||||
"icon": "links-going-out",
|
||||
"title": "Outgoing links"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "132e09c024f26162",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"followCursor": false,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-list",
|
||||
"title": "Outline"
|
||||
}
|
||||
}
|
||||
],
|
||||
"currentTab": 0
|
||||
},
|
||||
"left-ribbon": {
|
||||
"hiddenItems": {
|
||||
"switcher:Open quick switcher": false,
|
||||
"graph:Open graph view": false,
|
||||
"canvas:Create new canvas": false,
|
||||
"daily-notes:Open today's daily note": false,
|
||||
"templates:Insert template": false,
|
||||
"command-palette:Open command palette": false,
|
||||
"bases:Create new base": false
|
||||
}
|
||||
},
|
||||
"active": "dd3aa3882d71522e",
|
||||
"lastOpenFiles": []
|
||||
}
|
||||
202
doc/Aphelion/.obsidian/workspace.json
vendored
Normal file
202
doc/Aphelion/.obsidian/workspace.json
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
{
|
||||
"main": {
|
||||
"id": "b1b5384706f6944e",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "9bf552ce156753fa",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "aee743ac57c40a5d",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Tiers/Tier 4 - Astrophage and Interstellar Travel.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "Tier 4 - Astrophage and Interstellar Travel"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
},
|
||||
"left": {
|
||||
"id": "f83888d158679852",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "358b12ed12d59ae3",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "1f11e2a54128b8fa",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "file-explorer",
|
||||
"state": {
|
||||
"sortOrder": "alphabetical",
|
||||
"autoReveal": false
|
||||
},
|
||||
"icon": "lucide-folder-closed",
|
||||
"title": "Files"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "3c8e2b518b5b99e4",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "search",
|
||||
"state": {
|
||||
"query": "",
|
||||
"matchingCase": false,
|
||||
"explainSearch": false,
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical"
|
||||
},
|
||||
"icon": "lucide-search",
|
||||
"title": "Search"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "76ec0d5a263cf8dd",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "bookmarks",
|
||||
"state": {},
|
||||
"icon": "lucide-bookmark",
|
||||
"title": "Bookmarks"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300
|
||||
},
|
||||
"right": {
|
||||
"id": "e5dc1e339bc900c8",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "76abf2cf048a9890",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "0ace5339fb99d8fe",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"file": "Tier 3 — Transfer — Interplanetary Space Stations, Ion Propulsion.md",
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical",
|
||||
"showSearch": false,
|
||||
"searchQuery": "",
|
||||
"backlinkCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
},
|
||||
"icon": "links-coming-in",
|
||||
"title": "Backlinks for Tier 3 — Transfer — Interplanetary Space Stations, Ion Propulsion"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "973d50256169532a",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "outgoing-link",
|
||||
"state": {
|
||||
"file": "Tier 3 — Transfer — Interplanetary Space Stations, Ion Propulsion.md",
|
||||
"linksCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
},
|
||||
"icon": "links-going-out",
|
||||
"title": "Outgoing links from Tier 3 — Transfer — Interplanetary Space Stations, Ion Propulsion"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "2bd0942d425edc95",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "tag",
|
||||
"state": {
|
||||
"sortOrder": "frequency",
|
||||
"useHierarchy": true,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-tags",
|
||||
"title": "Tags"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "694a7d044328eb0a",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "all-properties",
|
||||
"state": {
|
||||
"sortOrder": "frequency",
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-archive",
|
||||
"title": "All properties"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "21b89c93ba0de8e3",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"file": "Tier 3 — Transfer — Interplanetary Space Stations, Ion Propulsion.md",
|
||||
"followCursor": false,
|
||||
"showSearch": false,
|
||||
"searchQuery": ""
|
||||
},
|
||||
"icon": "lucide-list",
|
||||
"title": "Outline of Tier 3 — Transfer — Interplanetary Space Stations, Ion Propulsion"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300,
|
||||
"collapsed": true
|
||||
},
|
||||
"left-ribbon": {
|
||||
"hiddenItems": {
|
||||
"switcher:Open quick switcher": false,
|
||||
"graph:Open graph view": false,
|
||||
"canvas:Create new canvas": false,
|
||||
"daily-notes:Open today's daily note": false,
|
||||
"templates:Insert template": false,
|
||||
"command-palette:Open command palette": false,
|
||||
"bases:Create new base": false
|
||||
}
|
||||
},
|
||||
"active": "aee743ac57c40a5d",
|
||||
"lastOpenFiles": [
|
||||
"Tiers/Tier 3 - Ion Propulsion and Fusion Power.md",
|
||||
"Tiers/Tier 2 - Orbits and Interplanetary Travel.md",
|
||||
"Tiers/Tier 1 - Beginning.md",
|
||||
"Tiers/Tier 5 - Warp.md",
|
||||
"Tiers/Tier 4 - Astrophage and Interstellar Travel.md",
|
||||
"Planets.md",
|
||||
"OLD/Tier 1 — Launch — Chemical Rocketry.md",
|
||||
"OLD/Tier 2 — Orbit — Nuclear Rocketry and Space Stations.md",
|
||||
"OLD/Tier 3 — Transfer — Interplanetary Space Stations, Ion Propulsion.md",
|
||||
"OLD/Tier 4 — Warp — Warp Technology and Fusion Power.md",
|
||||
"OLD",
|
||||
"Moon.md",
|
||||
"Tiers"
|
||||
]
|
||||
}
|
||||
0
doc/Aphelion/Planets.md
Normal file
0
doc/Aphelion/Planets.md
Normal file
16
doc/Aphelion/Tiers/Tier 1 - Beginning.md
Normal file
16
doc/Aphelion/Tiers/Tier 1 - Beginning.md
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
Gameplay goals:
|
||||
This tier represents the beginnings of the mod. Here we have basic rocketry, machinery, and materials. [[Rocket]]s enable travel between a [[Planets|Planet]] and its [[Moons]], as well as any other planetary satellites such as future [[Space Stations]].
|
||||
|
||||
Materials and Stuffs:
|
||||
[[Steel]] (Structural)
|
||||
[[Aluminum]] (Structural)
|
||||
[[Tin]]? (For electronics)
|
||||
[[Silicon]]? from Nether Quartz (For electronics) (Or use redstone and save silicon electronics for the modpack)
|
||||
Vanilla Ores (Copper, Iron, Gold)
|
||||
[[Oil]]
|
||||
|
||||
Machines:
|
||||
[[Electric Arc Furnace]] (Processing steel and other mod metals. Can be substituted by other mods recipes. I.E. IE, Mekanism, etc)
|
||||
[[Rocket Assembler]]
|
||||
[[Chemical Plant]]
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
Gameplay goals:
|
||||
This tier is marked by the construction of a [[Space Stations|Space Station]]. These platforms allow orbital bases, and [[Interplanetary Travel|interplanetary travel]]. [[Station Rocket Engine|Station rocket engines]] allow for [[rocket fuel]] powered propulsion to travel between [[Planets]]. Players are expected to have visited [[The Moon]] to obtain materials needed to construct a space station. [[Nuclear Power]] may also become available here. After unlocking interplanetary travel, materials needed to create [[Ion Engines]] become available.
|
||||
|
||||
Materials:
|
||||
[[Titanium]] (Structural)
|
||||
[[Uranium]] (Power)
|
||||
Cobalt (Secondary resource for reactors and alloys?)
|
||||
|
||||
Machines:
|
||||
[[Station Flight Computer]]
|
||||
[[Nuclear Fission Reactor]]
|
||||
[[Oxygen Distributor]]
|
||||
[[Gravity Generator]]
|
||||
[[Vacuum Arc Furnace]] (Titanium processing)
|
||||
[[Station Rocket Engine]]
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
Gameplay Goals: [[Ion Engines]] allow space stations to travel between planets without needing to ship up [[Rocket Fuel]], using FE to create propulsion directly, though providing slightly less thrust. To help with this power draw, [[Fusion Energy]] also becomes available here, which will be needed for [[Tier 4 - Astrophage and Interstellar Travel]].
|
||||
|
||||
Materials:
|
||||
[[Neodymium]] (Supermagnets for fusion and ion tech)
|
||||
[[Tungsten]] (Heat shielding for inside of fusion reactors, maybe add tungsten carbide? Complexity here can be saved for the modpack)
|
||||
Gasses such as [[Ammonia]], [[Helium-3]], and [[CO2]] from [[Gas Giant Skimmer|Gas Giant Skimming]]
|
||||
|
||||
Machines:
|
||||
[[Fusion Energy|Fusion Reactor]]
|
||||
[[Ion Engines]]
|
||||
[[Gas Giant Skimmer]]
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
Gameplay Goals: Having mastered interplanetary travel, [[Astrophage]] presents itself as the ultimate fuel source. Capable of converting mass directly into energy, interstellar travel is now possible only using a few grams of fuel per hour. It can either be collected from space or or bred. Breeding astrophage requires inputting massive amounts of energy to "charge" it. Some small amount will need to be acquired naturally before it can be bred.
|
||||
|
||||
Materials:
|
||||
[[Astrophage]]
|
||||
|
||||
Machines:
|
||||
[[Spin Drive]] (Astrophage powered engines, uses CO2 lasers to excite the astrophage into providing thrust)
|
||||
[[Astrophage Collector]] (For collecting from a [[Petrova Line]])
|
||||
[[Astrophage Breeder]]
|
||||
2
doc/Aphelion/Tiers/Tier 5 - Warp.md
Normal file
2
doc/Aphelion/Tiers/Tier 5 - Warp.md
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
Speculative
|
||||
22
doc/OLD/Tier 1 — Launch — Chemical Rocketry.md
Normal file
22
doc/OLD/Tier 1 — Launch — Chemical Rocketry.md
Normal file
@@ -0,0 +1,22 @@
|
||||
Materials and Stuffs:
|
||||
[[Steel]] from Coal and Iron in [[Electric Arc Furnace]]
|
||||
[[Aluminum]]
|
||||
[[Tin]]
|
||||
[[Silicon]] from Nether Quartz
|
||||
Vanilla Ores (Copper, Iron, Gold)
|
||||
[[Oil]]
|
||||
|
||||
Machines:
|
||||
[[Generators]]
|
||||
[[Solar Panels]]
|
||||
[[Electric Arc Furnace]]
|
||||
[[Chemical Plant]]
|
||||
[[Rocket Assembler]]
|
||||
[[Launch Pad]]
|
||||
|
||||
Technologies:
|
||||
[[Simple Electronics]]
|
||||
|
||||
Milestones:
|
||||
[[Liquid Propellent Rocket]]
|
||||
Travel to the moon
|
||||
@@ -0,0 +1,17 @@
|
||||
Materials:
|
||||
[[Titanium]]
|
||||
[[Uranium]]
|
||||
[[Cobalt]]
|
||||
|
||||
Machines:
|
||||
???
|
||||
|
||||
Technologies:
|
||||
[[Nuclear Fission Reactors]]
|
||||
???
|
||||
|
||||
Milestones:
|
||||
[[Nuclear Thermal Rocket]] maybe?
|
||||
[[Space Stations]]
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
Materials:
|
||||
[[Tungsten]]
|
||||
[[Neodymium]]
|
||||
|
||||
Machines:
|
||||
[[Gas Giant Skimmer]]
|
||||
|
||||
Technologies:
|
||||
[[Ion Engines]]
|
||||
[[Gas Giant Harvesting]]
|
||||
|
||||
Milestones:
|
||||
Interplanetary Space Station Travel via Ion Engines
|
||||
16
doc/OLD/Tier 4 — Warp — Warp Technology and Fusion Power.md
Normal file
16
doc/OLD/Tier 4 — Warp — Warp Technology and Fusion Power.md
Normal file
@@ -0,0 +1,16 @@
|
||||
Materials and Stuffs:
|
||||
[[Iridium]]
|
||||
[[Helium-3]]
|
||||
|
||||
Machines:
|
||||
???
|
||||
|
||||
Technologies:
|
||||
[[Fusion Energy]]
|
||||
[[Alcubierre Drives]]
|
||||
|
||||
Milestones:
|
||||
Interstellar Travel
|
||||
Limitless Interplanetary Travel
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public class StationFlightComputerBlock extends BasicHorizontalEntityBlock {
|
||||
|
||||
@Override
|
||||
protected void onRemove(BlockState state, @NotNull Level level, @NotNull BlockPos pos, BlockState newState, boolean movedByPiston) {
|
||||
super.onRemove(state, level, pos, newState, movedByPiston);
|
||||
if (level.getBlockEntity(pos) instanceof StationFlightComputerBlockEntity computerBE) {
|
||||
PartitionData data = computerBE.getData();
|
||||
if (data != null) {
|
||||
@@ -39,4 +40,15 @@ public class StationFlightComputerBlock extends BasicHorizontalEntityBlock {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
|
||||
super.onPlace(state, level, pos, oldState, movedByPiston);
|
||||
if (level.getBlockEntity(pos) instanceof StationFlightComputerBlockEntity computerBE) {
|
||||
PartitionData data = computerBE.getData();
|
||||
if (data != null) {
|
||||
data.setTraveling(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ public class StationFlightComputerBlockEntity extends BlockEntity implements Tic
|
||||
|
||||
@Override
|
||||
public void serverTick(ServerLevel level, long time, BlockState state, BlockPos pos) {
|
||||
if (data == null) return;
|
||||
data.setTraveling(true);
|
||||
}
|
||||
|
||||
public @Nullable PartitionData getData() {
|
||||
@@ -42,7 +40,7 @@ public class StationFlightComputerBlockEntity extends BlockEntity implements Tic
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
if (serverLevel.dimension() == ModDimensions.SPACE) {
|
||||
data = SpacePartitionSavedData.get(serverLevel).getDataForBlockPos(pos);
|
||||
|
||||
setTraveling(true);
|
||||
}
|
||||
}
|
||||
isInitialized = true;
|
||||
|
||||
@@ -54,8 +54,8 @@ public class StationRocketEngineBlockEntity extends StationEngineBlockEntity {
|
||||
|
||||
if (data.getDestination() != null && data.isTraveling()) {
|
||||
if (!tank.isEmpty() && tank.getFluid().is(ModFluidTags.ROCKET_FUEL) && tank.getFluidAmount() >= FUEL_CONSUMPTION) { // has enough fuel?
|
||||
if (data.travel(getTravelSpeed()))
|
||||
tank.drain(FUEL_CONSUMPTION, IFluidHandler.FluidAction.EXECUTE);
|
||||
data.travel(getTravelSpeed());
|
||||
tank.drain(FUEL_CONSUMPTION, IFluidHandler.FluidAction.EXECUTE);
|
||||
} else {
|
||||
// not enough fuel
|
||||
}
|
||||
|
||||
@@ -54,4 +54,11 @@ public abstract class StationEngineBlockEntity extends BlockEntity implements Ti
|
||||
}
|
||||
isInitialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved() {
|
||||
if (data != null)
|
||||
data.removeEngine(worldPosition);
|
||||
TickableBlockEntity.super.onRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.neoforge.client.event.CustomizeGuiOverlayEvent;
|
||||
import net.xevianlight.aphelion.Aphelion;
|
||||
import net.xevianlight.aphelion.client.dimension.DimensionRenderer;
|
||||
@@ -14,8 +14,12 @@ import net.xevianlight.aphelion.client.dimension.DimensionRendererCache;
|
||||
import net.xevianlight.aphelion.client.dimension.SpaceSkyEffects;
|
||||
import net.xevianlight.aphelion.core.saveddata.EnvironmentSavedData;
|
||||
import net.xevianlight.aphelion.core.saveddata.SpacePartitionSavedData;
|
||||
import net.xevianlight.aphelion.planet.Planet;
|
||||
import net.xevianlight.aphelion.planet.PlanetCache;
|
||||
import net.xevianlight.aphelion.util.SpacePartition;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@EventBusSubscriber(modid = Aphelion.MOD_ID, value = Dist.CLIENT)
|
||||
public class AphelionDebugOverlay {
|
||||
|
||||
@@ -46,19 +50,28 @@ public class AphelionDebugOverlay {
|
||||
int x = SpacePartition.get(Math.floor(mc.player.position().x));
|
||||
int z = SpacePartition.get(Math.floor(mc.player.position().z));
|
||||
|
||||
ResourceLocation orbit = PartitionClientState.lastData().getOrbit();
|
||||
Planet planet = PlanetCache.getByOrbitOrDefault(orbit);
|
||||
var dimension = planet.dimension();
|
||||
|
||||
// Left side of F3
|
||||
event.getLeft().add("");
|
||||
event.getLeft().add("Aphelion:");
|
||||
event.getLeft().add(" Orbit: " + PartitionClientState.lastData().getOrbit());
|
||||
event.getLeft().add(" Orbit: " + orbit);
|
||||
event.getLeft().add(" Planet: " + PlanetCache.getByOrbitOrNull(orbit));
|
||||
event.getLeft().add(" Associated Dimension: " + dimension.location().toString());
|
||||
// event.getLeft().add(" Sky: " + rendererSummary);
|
||||
event.getLeft().add(" Station: " + x + " " + z + " ID: " + SpacePartitionSavedData.pack(x,z));
|
||||
event.getLeft().add(" Station Destination: " + PartitionClientState.lastData().getDestination());
|
||||
event.getLeft().add(" Station Destination AU: " + PlanetCache.getOrDefault(PartitionClientState.lastData().getDestination()).orbitDistance());
|
||||
event.getLeft().add(" Station Owner: " + PartitionClientState.lastData().getOwner());
|
||||
event.getLeft().add(" Station Engines: " + PartitionClientState.lastData().getEngines().toArray().length);
|
||||
event.getLeft().add(" Station Engines: " + Arrays.toString(PartitionClientState.lastData().getEngines().toArray()));
|
||||
event.getLeft().add(" Station Landing Pads: " + PartitionClientState.lastData().getLandingPadContollersAsArray().length);
|
||||
event.getLeft().add(" Station Traveling: " + PartitionClientState.lastData().isTraveling());
|
||||
event.getLeft().add(" Station Orbital Distance AU: " + PartitionClientState.lastData().getOrbitDistance());
|
||||
event.getLeft().add(" Station Trip Distance AU: " + PartitionClientState.lastData().getTripDistanceAU());
|
||||
event.getLeft().add(" Station Distance Traveled AU: " + PartitionClientState.lastData().getDistanceTraveledAU());
|
||||
event.getLeft().add(" Station Trip Traveled AU: " + PartitionClientState.lastData().getDistanceTraveledAU());
|
||||
event.getLeft().add(" Station PosData: " + PartitionClientState.lastData().getPosData().toString());
|
||||
var server = mc.getSingleplayerServer();
|
||||
ServerLevel singlePlayerLevel;
|
||||
if (server != null) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.saveddata.SavedData;
|
||||
import net.xevianlight.aphelion.Aphelion;
|
||||
import net.xevianlight.aphelion.core.saveddata.types.PartitionData;
|
||||
import net.xevianlight.aphelion.core.saveddata.types.PosData;
|
||||
import net.xevianlight.aphelion.util.SpacePartition;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -74,6 +75,14 @@ public class SpacePartitionSavedData extends SavedData {
|
||||
pd.setLandingPadContollersFromArray(e.getLongArray("LandingPads"));
|
||||
}
|
||||
|
||||
if (e.contains("PosData", CompoundTag.TAG_LONG)) {
|
||||
pd.setPosData(PosData.unpacker(e.getLong("PosData")));
|
||||
}
|
||||
|
||||
if (e.contains("OrbitDistance", CompoundTag.TAG_DOUBLE)) {
|
||||
pd.setOrbitDistance(e.getDouble("OrbitDistance"));
|
||||
}
|
||||
|
||||
data.map.put(key, pd);
|
||||
}
|
||||
|
||||
@@ -115,6 +124,10 @@ public class SpacePartitionSavedData extends SavedData {
|
||||
|
||||
e.putLongArray("LandingPads", pd.getLandingPadContollersAsArray());
|
||||
|
||||
e.putLong("PosData", pd.getPosDataOrDefault().pack());
|
||||
|
||||
e.putDouble("OrbitDistance", pd.getOrbitDistance());
|
||||
|
||||
entries.add(e);
|
||||
});
|
||||
|
||||
@@ -178,10 +191,11 @@ public class SpacePartitionSavedData extends SavedData {
|
||||
if (data == null) {
|
||||
|
||||
// pick a sensible default orbit, or null if you truly allow it
|
||||
data = new PartitionData(Aphelion.id("orbit/default"));
|
||||
data = new PartitionData(Aphelion.id("orbit/unassigned"));
|
||||
map.put(key, data);
|
||||
setDirty();
|
||||
}
|
||||
data.setDirtyCallback(this::setDirty);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -210,6 +224,7 @@ public class SpacePartitionSavedData extends SavedData {
|
||||
map.put(key, data);
|
||||
setDirty();
|
||||
}
|
||||
data.setDirtyCallback(this::setDirty);
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -237,6 +252,7 @@ public class SpacePartitionSavedData extends SavedData {
|
||||
map.put(key, data);
|
||||
setDirty();
|
||||
}
|
||||
data.setDirtyCallback(this::setDirty);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@ package net.xevianlight.aphelion.core.saveddata.types;
|
||||
|
||||
public record EnvironmentData (boolean oxygen, short temperature, float gravity){
|
||||
|
||||
|
||||
|
||||
public static final boolean DEFAULT_OXYGEN = true;
|
||||
public static final short DEFAULT_TEMPERATURE = (short) 294.2611; // 70F
|
||||
public static final float DEFAULT_GRAVITY = 9.80665f; // 1G
|
||||
|
||||
@@ -6,6 +6,7 @@ import net.minecraft.core.UUIDUtil;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.xevianlight.aphelion.planet.Planet;
|
||||
import net.xevianlight.aphelion.planet.PlanetCache;
|
||||
import net.xevianlight.aphelion.util.BigCodec;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -18,24 +19,32 @@ public class PartitionData {
|
||||
|
||||
@Nullable private ResourceLocation orbit;
|
||||
@Nullable private ResourceLocation destination;
|
||||
@Nullable private ResourceLocation system;
|
||||
private boolean traveling;
|
||||
/// How far we've already gone
|
||||
private double distanceTraveledAU;
|
||||
/// Total trip distance, from start to finish
|
||||
/// Total trip distance, from start to finish. Used with distanceTraveledAU to determine trip progress for UI or other. Not used in trip calculation.
|
||||
private double tripDistanceAU;
|
||||
private boolean generated;
|
||||
private UUID owner;
|
||||
private List<BlockPos> landingPadControllers;
|
||||
private List<BlockPos> engines;
|
||||
private double currentOrbitDistanceAU;
|
||||
/// Data object containing station rotation.
|
||||
private PosData posData;
|
||||
private double orbitDistance;
|
||||
|
||||
/// Cache the planet that corresponds to our orbit so we don't have to constantly look it up from PlanetCache. Will be accurate as long as setOrbit() is used exclusively.
|
||||
@Nullable private Planet cachedPlanet;
|
||||
/// Cache the planet that corresponds to our destination so we don't have to constantly look it up from PlanetCache. Will be accurate as long as setDestination() is used exclusively.
|
||||
@Nullable private Planet cachedDestination;
|
||||
|
||||
public PartitionData() {
|
||||
|
||||
}
|
||||
|
||||
public PartitionData(@Nullable ResourceLocation orbit) {
|
||||
this.orbit = orbit;
|
||||
this.destination = null;
|
||||
setOrbit(orbit);
|
||||
setDestination(null);
|
||||
this.traveling = false;
|
||||
this.distanceTraveledAU = 0;
|
||||
this.tripDistanceAU = 0;
|
||||
@@ -43,18 +52,25 @@ public class PartitionData {
|
||||
this.owner = null;
|
||||
this.landingPadControllers = List.of();
|
||||
this.engines = new ArrayList<>(List.of());
|
||||
this.posData = new PosData();
|
||||
setOrbitDistance(1);
|
||||
}
|
||||
|
||||
public PartitionData(PartitionData other) {
|
||||
this.orbit = other.orbit;
|
||||
this.cachedPlanet = other.cachedPlanet;
|
||||
this.destination = other.destination;
|
||||
this.cachedDestination = other.cachedDestination;
|
||||
this.traveling = other.traveling;
|
||||
this.distanceTraveledAU = other.distanceTraveledAU;
|
||||
this.tripDistanceAU = other.tripDistanceAU;
|
||||
this.tripDistanceAU = other.tripDistanceAU; // copy directly, no recalculation
|
||||
this.generated = other.generated;
|
||||
this.owner = other.owner;
|
||||
this.landingPadControllers = other.landingPadControllers;
|
||||
this.engines = other.engines;
|
||||
this.engines = other.getEngines(); // defensive copy
|
||||
this.landingPadControllers = other.getLandingPadControllers();
|
||||
this.posData = other.posData;
|
||||
this.orbitDistance = other.orbitDistance;
|
||||
// don't set dirty callback — caller must do that
|
||||
}
|
||||
|
||||
public static final StreamCodec<ByteBuf, PartitionData> STREAM_CODEC =
|
||||
@@ -66,6 +82,9 @@ public class PartitionData {
|
||||
ByteBufCodecs.optional(ResourceLocation.STREAM_CODEC),
|
||||
d -> Optional.ofNullable(d.getDestination()),
|
||||
|
||||
ByteBufCodecs.optional(ResourceLocation.STREAM_CODEC),
|
||||
d -> Optional.ofNullable(d.getSystem()),
|
||||
|
||||
ByteBufCodecs.BOOL,
|
||||
PartitionData::isTraveling,
|
||||
|
||||
@@ -88,9 +107,16 @@ public class PartitionData {
|
||||
BLOCKPOS_LIST_CODEC,
|
||||
PartitionData::getEngines,
|
||||
|
||||
(orbitOpt, destOpt, traveling, distTraveled, distToDest, ownerOpt, generated, controllers, engines) -> {
|
||||
ByteBufCodecs.VAR_LONG,
|
||||
PartitionData::getPosDataPacked,
|
||||
|
||||
ByteBufCodecs.DOUBLE,
|
||||
PartitionData::getOrbitDistance,
|
||||
|
||||
(orbitOpt, destOpt, systemOpt, traveling, distTraveled, distToDest, ownerOpt, generated, controllers, engines, posData, distance) -> {
|
||||
PartitionData data = new PartitionData(orbitOpt.orElse(null));
|
||||
data.destination = destOpt.orElse(null);
|
||||
data.setDestination(destOpt.orElse(null));
|
||||
data.setSystem(systemOpt.orElse(null));
|
||||
data.traveling = traveling;
|
||||
data.distanceTraveledAU = distTraveled;
|
||||
data.tripDistanceAU = distToDest;
|
||||
@@ -98,28 +124,51 @@ public class PartitionData {
|
||||
data.generated = generated;
|
||||
data.landingPadControllers = controllers;
|
||||
data.engines = engines;
|
||||
data.posData = PosData.unpacker(posData);
|
||||
data.setOrbitDistance(distance);
|
||||
return data;
|
||||
}
|
||||
);
|
||||
|
||||
private Long getPosDataPacked() {
|
||||
if (posData == null) posData = new PosData();
|
||||
return posData.pack();
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getOrbit() {
|
||||
return this.orbit;
|
||||
}
|
||||
|
||||
public void setOrbit(@Nullable ResourceLocation orbit) {
|
||||
this.orbit = orbit;
|
||||
cachedPlanet = PlanetCache.getByOrbitOrNull(orbit);
|
||||
if (cachedPlanet != null && this.posData != null)
|
||||
setOrbitDistance(cachedPlanet.orbitDistance());
|
||||
recalculateTripDistAU();
|
||||
distanceTraveledAU = 0;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getDestination() {
|
||||
cachedDestination = PlanetCache.getOrNull(destination);
|
||||
return destination;
|
||||
}
|
||||
|
||||
public void setDestination(@Nullable ResourceLocation destination) {
|
||||
this.destination = destination;
|
||||
cachedDestination = PlanetCache.getOrNull(destination);
|
||||
recalculateTripDistAU();
|
||||
distanceTraveledAU = 0;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public @Nullable ResourceLocation getSystem() {
|
||||
return system;
|
||||
}
|
||||
|
||||
public void setSystem(@Nullable ResourceLocation system) {
|
||||
this.system = system;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public boolean isTraveling() {
|
||||
@@ -127,7 +176,9 @@ public class PartitionData {
|
||||
}
|
||||
|
||||
public void setTraveling(boolean traveling) {
|
||||
if (this.traveling == traveling) return;
|
||||
this.traveling = traveling;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public double getDistanceTraveledAU() {
|
||||
@@ -136,11 +187,13 @@ public class PartitionData {
|
||||
|
||||
public void setDistanceTraveledAU(double distanceTraveledAU) {
|
||||
this.distanceTraveledAU = distanceTraveledAU;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public double recalculateTripDistAU() {
|
||||
var currentPlanet = PlanetCache.getByOrbitOrNull(orbit);
|
||||
if (currentPlanet == null) {
|
||||
markDirty();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -148,6 +201,7 @@ public class PartitionData {
|
||||
|
||||
var dist = destPlanet.orbitDistance() - currentPlanet.orbitDistance();
|
||||
this.tripDistanceAU = dist;
|
||||
markDirty();
|
||||
return dist;
|
||||
}
|
||||
|
||||
@@ -155,6 +209,20 @@ public class PartitionData {
|
||||
return tripDistanceAU;
|
||||
}
|
||||
|
||||
public double getTripDeltaAU() {
|
||||
if (cachedDestination == null) return 0;
|
||||
return cachedDestination.orbitDistance() - orbitDistance;
|
||||
}
|
||||
|
||||
public double getOrbitDistance() {
|
||||
return orbitDistance;
|
||||
}
|
||||
|
||||
public void setOrbitDistance(double orbitDistance) {
|
||||
this.orbitDistance = orbitDistance;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public void setTripDistanceAU(double tripDistanceAU) {
|
||||
this.tripDistanceAU = tripDistanceAU;
|
||||
}
|
||||
@@ -162,26 +230,38 @@ public class PartitionData {
|
||||
/**
|
||||
* Advances travel progress by the specified distance in AU.
|
||||
*
|
||||
* <p>This increases {@code distanceTraveledAU} by the given amount and clamps
|
||||
* the result so it never exceeds {@code tripDistanceAU}.</p>
|
||||
*
|
||||
* <p>If the requested distance would overshoot the destination, the traveled
|
||||
* distance is set to exactly {@code tripDistanceAU}.</p>
|
||||
* <p>Each call moves the station's current AU position toward the destination
|
||||
* planet's AU value by the given amount. If the step would overshoot, the
|
||||
* position is clamped to the destination exactly and arrival is triggered.</p>
|
||||
*
|
||||
* @param distance the distance to advance in astronomical units (AU)
|
||||
* @return {@code true} when we arrive at our destination, {@code false} otherwise.
|
||||
* @return {@code true} when the station has arrived at its destination,
|
||||
* {@code false} if travel is still in progress.
|
||||
*/
|
||||
public boolean travel(double distance) {
|
||||
if (distanceTraveledAU + distance > tripDistanceAU) {
|
||||
if (cachedDestination == null) return false;
|
||||
if (cachedPlanet == null) return false;
|
||||
|
||||
double delta = getTripDeltaAU();
|
||||
double step = distance * Math.signum(delta);
|
||||
|
||||
if (Math.abs(delta) <= distance) {
|
||||
this.orbitDistance = (cachedDestination.orbitDistance());
|
||||
this.orbit = cachedDestination.orbit().location();
|
||||
this.cachedPlanet = cachedDestination;
|
||||
this.destination = null;
|
||||
this.cachedDestination = null;
|
||||
this.traveling = false;
|
||||
distanceTraveledAU = tripDistanceAU;
|
||||
var destinationPlanet = PlanetCache.getOrNull(destination);
|
||||
if (destinationPlanet != null) {
|
||||
setOrbit(destinationPlanet.orbit().location());
|
||||
}
|
||||
return false;
|
||||
|
||||
markDirty();
|
||||
return true;
|
||||
} else {
|
||||
distanceTraveledAU += distance;
|
||||
return true;
|
||||
this.orbitDistance += step;
|
||||
|
||||
markDirty();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,6 +271,7 @@ public class PartitionData {
|
||||
|
||||
public void setGenerated(boolean generated) {
|
||||
this.generated = generated;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
public @Nullable UUID getOwner() {
|
||||
@@ -199,6 +280,7 @@ public class PartitionData {
|
||||
|
||||
public void setOwner(@Nullable UUID owner) {
|
||||
this.owner = owner;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -222,6 +304,7 @@ public class PartitionData {
|
||||
|
||||
public void setLandingPadControllers(List<BlockPos> landingPadControllers) {
|
||||
this.landingPadControllers = landingPadControllers;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
|
||||
@@ -254,7 +337,11 @@ public class PartitionData {
|
||||
* @return {@code true} if a controller was removed, {@code false} otherwise
|
||||
*/
|
||||
public boolean removeLandingPadController(BlockPos pos) {
|
||||
return landingPadControllers.remove(pos);
|
||||
if (landingPadControllers.remove(pos)) {
|
||||
markDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -279,6 +366,7 @@ public class PartitionData {
|
||||
|
||||
public void setEngines(List<BlockPos> engines) {
|
||||
this.engines = engines;
|
||||
markDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -294,13 +382,18 @@ public class PartitionData {
|
||||
public boolean addEngine(BlockPos pos) {
|
||||
if (!engines.contains(pos)) {
|
||||
engines.add(pos);
|
||||
markDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean removeEngine(BlockPos pos) {
|
||||
return engines.remove(pos);
|
||||
if (engines.remove(pos)) {
|
||||
markDirty();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -314,9 +407,14 @@ public class PartitionData {
|
||||
&& Objects.equals(this.destination, that.destination)
|
||||
&& this.traveling == that.traveling
|
||||
&& Double.compare(this.distanceTraveledAU, that.distanceTraveledAU) == 0
|
||||
&& Double.compare(this.tripDistanceAU, that.tripDistanceAU) == 0
|
||||
&& Double.compare(this.orbitDistance, that.orbitDistance) == 0
|
||||
&& this.generated == that.generated
|
||||
&& Objects.equals(this.owner, that.owner);
|
||||
&& Objects.equals(this.owner, that.owner)
|
||||
&& Objects.equals(this.engines, that.engines)
|
||||
&& Objects.equals(this.landingPadControllers, that.landingPadControllers);
|
||||
/* tripDistanceAU intentionally excluded — it is a derived value computed from
|
||||
* orbit and destination, and may fluctuate due to recalculation timing.
|
||||
* It should never drive packet equality decisions. */
|
||||
}
|
||||
|
||||
public long[] getLandingPadContollersAsArray() {
|
||||
@@ -336,6 +434,31 @@ public class PartitionData {
|
||||
newList.add(BlockPos.of(packedPos));
|
||||
i++;
|
||||
}
|
||||
markDirty();
|
||||
setLandingPadControllers(newList);
|
||||
}
|
||||
|
||||
public PosData getPosData() {
|
||||
return posData;
|
||||
}
|
||||
|
||||
public PosData getPosDataOrDefault() {
|
||||
if (posData == null) return new PosData();
|
||||
return posData;
|
||||
}
|
||||
|
||||
public void setPosData(PosData posData) {
|
||||
markDirty();
|
||||
this.posData = posData;
|
||||
}
|
||||
|
||||
private Runnable onDirty;
|
||||
|
||||
public void setDirtyCallback(Runnable onDirty) {
|
||||
this.onDirty = onDirty;
|
||||
}
|
||||
|
||||
private void markDirty() {
|
||||
if (onDirty != null) onDirty.run();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
package net.xevianlight.aphelion.core.saveddata.types;
|
||||
|
||||
import org.joml.Vector3f;
|
||||
|
||||
/**
|
||||
* Stores the positional and rotational data for a space station.
|
||||
*
|
||||
* <p>Rotation is stored as three 16-bit fixed-point values (pitch, yaw, roll),
|
||||
* where {@code 0} maps to {@code 0°} and {@code 65536} maps to {@code 360°}.
|
||||
* This representation allows angle arithmetic to wrap correctly via natural
|
||||
* short overflow, with no explicit modulo required.
|
||||
*
|
||||
* <p>All four fields (pitch, yaw, roll, distance) can be packed into a single
|
||||
* {@code long} for efficient NBT storage.
|
||||
*
|
||||
* @see #pack()
|
||||
* @see #packer(PosData)
|
||||
* @see #unpacker(long)
|
||||
*/
|
||||
public class PosData {
|
||||
|
||||
public static final float AU_SCALE = 1.0f / 512.0f;
|
||||
|
||||
/// Fixed-point pitch rotation. {@code 0} = 0°, {@code 32768} = 180°. <p>{@code 0.005493°} precision.
|
||||
public short pitch;
|
||||
/// Fixed-point yaw rotation. {@code 0} = 0°, {@code 32768} = 180°. <p>{@code 0.005493°} precision.
|
||||
public short yaw;
|
||||
/// Fixed-point roll rotation. {@code 0} = 0°, {@code 32768} = 180°. <p>{@code 0.005493°} precision.
|
||||
public short roll;
|
||||
/**
|
||||
* Orbital distance, stored as an unsigned 16-bit value. <p> {@code 0.00195 AU} precision.
|
||||
* <p>Defaults to {@code 1 AU}.
|
||||
*/
|
||||
|
||||
public PosData() {
|
||||
pitch = 0;
|
||||
yaw = 0;
|
||||
roll = 0;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public PosData(short pitch, short yaw, short roll) {
|
||||
this.pitch = fromDegrees(pitch);
|
||||
this.yaw = yaw;
|
||||
this.roll = roll;
|
||||
}
|
||||
|
||||
public PosData(PosData other) {
|
||||
this.pitch = other.pitch;
|
||||
this.yaw = other.yaw;
|
||||
this.roll = other.roll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Packs this instance into a single {@code long} for NBT storage.
|
||||
*
|
||||
* @return the packed {@code long} representation
|
||||
* @see #packer(PosData)
|
||||
*/
|
||||
public long pack() {
|
||||
return packer(this);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Packs a {@code PosData} into a single {@code long}.
|
||||
*
|
||||
* <p>Layout (low to high bits):
|
||||
* <pre>
|
||||
* [0..15] pitch
|
||||
* [16..31] yaw
|
||||
* [32..47] roll
|
||||
* [48..63] distance
|
||||
* </pre>
|
||||
*
|
||||
* @param data the {@code PosData} to pack
|
||||
* @return the packed {@code long}
|
||||
*/
|
||||
public static long packer(PosData data) {
|
||||
return ((long) data.pitch & 0xFFFFL )
|
||||
| (((long) data.yaw & 0xFFFFL) << 16)
|
||||
| (((long) data.roll & 0xFFFFL) << 32);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks a {@code long} into a new {@code PosData} instance.
|
||||
*
|
||||
* @param packed the {@code long} to unpack, as produced by {@link #packer(PosData)}
|
||||
* @return a new {@code PosData} with fields restored from the packed value
|
||||
*/
|
||||
public static PosData unpacker(long packed) {
|
||||
PosData data = new PosData();
|
||||
data.pitch = (short) (packed & 0xFFFFL);
|
||||
data.yaw = (short) ((packed >> 16) & 0xFFFFL);
|
||||
data.roll = (short) ((packed >> 32) & 0xFFFFL);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a degree value to the fixed-point short representation.
|
||||
*
|
||||
* <p>{@code 0°} maps to {@code 0}, {@code 360°} maps to {@code 65536}
|
||||
* (which overflows to {@code 0}, preserving wrap-around correctness).
|
||||
*
|
||||
* @param degrees the angle in degrees
|
||||
* @return the fixed-point short representation
|
||||
*/
|
||||
public static short fromDegrees(float degrees) {
|
||||
return (short) Math.round((degrees / 360.0f) * 65536.0f);
|
||||
}
|
||||
|
||||
public static float pitchDegrees(PosData data) { return toDegrees(data.pitch); }
|
||||
public static float yawDegrees(PosData data) { return toDegrees(data.yaw); }
|
||||
public static float rollDegrees(PosData data) { return toDegrees(data.roll); }
|
||||
|
||||
public float pitchDegrees() { return toDegrees(pitch); }
|
||||
public float yawDegrees() { return toDegrees(yaw); }
|
||||
public float rollDegrees() { return toDegrees(roll); }
|
||||
|
||||
/**
|
||||
* Converts a fixed-point short to degrees.
|
||||
*
|
||||
* @param s the fixed-point value
|
||||
* @return the angle in degrees, in the range {@code [0°, 360°)}
|
||||
*/
|
||||
private static float toDegrees(short s) {
|
||||
return ((s & 0xFFFF) / 65536.0f) * 360.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a fixed-point short to radians.
|
||||
*
|
||||
* @param s the fixed-point value
|
||||
* @return the angle in radians, in the range {@code [0, 2π)}
|
||||
*/
|
||||
private static float toRadians(short s) {
|
||||
return ((s & 0xFFFF) / 65536.0f) * (float) (2 * Math.PI);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Euler angles (for rendering)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns the rotation as a {@link Vector3f} of Euler angles in degrees
|
||||
* ({@code x} = pitch, {@code y} = yaw, {@code z} = roll).
|
||||
*
|
||||
* @return Euler angles in degrees
|
||||
*/
|
||||
public Vector3f eulerAnglesDeg() {
|
||||
return new Vector3f(pitchDegrees(), yawDegrees(), rollDegrees());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rotation of the given {@code PosData} as a {@link Vector3f}
|
||||
* of Euler angles in degrees ({@code x} = pitch, {@code y} = yaw, {@code z} = roll).
|
||||
*
|
||||
* @param data the instance to read from
|
||||
* @return Euler angles in degrees
|
||||
*/
|
||||
public static Vector3f eulerAnglesDeg(PosData data) {
|
||||
return new Vector3f(pitchDegrees(data), yawDegrees(data), rollDegrees(data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rotation as a {@link Vector3f} of Euler angles in radians
|
||||
* ({@code x} = pitch, {@code y} = yaw, {@code z} = roll).
|
||||
* Suitable for direct use with JOML rotation methods.
|
||||
*
|
||||
* @return Euler angles in radians
|
||||
*/
|
||||
public Vector3f eulerAnglesRad() {
|
||||
return new Vector3f(toRadians(pitch), toRadians(yaw), toRadians(roll));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rotation of the given {@code PosData} as a {@link Vector3f}
|
||||
* of Euler angles in radians ({@code x} = pitch, {@code y} = yaw, {@code z} = roll).
|
||||
* Suitable for direct use with JOML rotation methods.
|
||||
*
|
||||
* @param data the instance to read from
|
||||
* @return Euler angles in radians
|
||||
*/
|
||||
public static Vector3f eulerAnglesRad(PosData data) {
|
||||
return new Vector3f(toRadians(data.pitch), toRadians(data.yaw), toRadians(data.roll));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Setters from degrees (convenience)
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public void setPitchDegrees(float degrees) { this.pitch = fromDegrees(degrees); }
|
||||
public void setYawDegrees(float degrees) { this.yaw = fromDegrees(degrees); }
|
||||
public void setRollDegrees(float degrees) { this.roll = fromDegrees(degrees); }
|
||||
|
||||
public void addPitchDegrees(float degrees) { this.pitch += fromDegrees(degrees); }
|
||||
public void addYawDegrees(float degrees) { this.yaw += fromDegrees(degrees); }
|
||||
public void addRollDegrees(float degrees) { this.roll += fromDegrees(degrees); }
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Utility
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Returns a human-readable representation of this {@code PosData},
|
||||
* with rotations in degrees and distance as an unsigned integer.
|
||||
*
|
||||
* @return a formatted string representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PosData{pitch=%.2f°, yaw=%.2f°, roll=%.2f°}"
|
||||
.formatted(pitchDegrees(), yawDegrees(), rollDegrees());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -34,8 +34,15 @@ public final class PartitionSync {
|
||||
|
||||
// If it is different, send them the new one
|
||||
if (prev == null || !prev.equals(now)) {
|
||||
Aphelion.LOGGER.debug("Partition changed for {}: prev={} now={}", sp.getName().getString(),
|
||||
prev == null ? "null" : String.format("orbit=%s dest=%s traveling=%s distTraveled=%s tripDist=%s orbitDist=%s",
|
||||
prev.partitionData().getOrbit(), prev.partitionData().getDestination(), prev.partitionData().isTraveling(),
|
||||
prev.partitionData().getDistanceTraveledAU(), prev.partitionData().getTripDistanceAU(), prev.partitionData().getOrbitDistance()),
|
||||
String.format("orbit=%s dest=%s traveling=%s distTraveled=%s tripDist=%s orbitDist=%s",
|
||||
now.partitionData().getOrbit(), now.partitionData().getDestination(), now.partitionData().isTraveling(),
|
||||
now.partitionData().getDistanceTraveledAU(), now.partitionData().getTripDistanceAU(), now.partitionData().getOrbitDistance())
|
||||
);
|
||||
PacketDistributor.sendToPlayer(sp, now);
|
||||
// Store this packet for later
|
||||
LAST_SENT.put(sp.getUUID(), now);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,13 +7,16 @@ import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.xevianlight.aphelion.util.registries.ModRegistries;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public record Planet (
|
||||
ResourceKey<Level> dimension,
|
||||
ResourceKey<Orbit> orbit,
|
||||
double orbitDistance,
|
||||
ResourceKey<StarSystem> system,
|
||||
boolean oxygen,
|
||||
float gravity
|
||||
float gravity,
|
||||
Optional<ResourceKey<Planet>> parentPlanet /// nullable moon parent
|
||||
) {
|
||||
public static final Codec<Planet> CODEC = RecordCodecBuilder.create(inst -> inst.group(
|
||||
ResourceKey.codec(Registries.DIMENSION).fieldOf("dimension").forGetter(Planet::dimension),
|
||||
@@ -21,7 +24,8 @@ public record Planet (
|
||||
Codec.DOUBLE.fieldOf("orbit_distance").forGetter(Planet::orbitDistance),
|
||||
ResourceKey.codec(ModRegistries.STAR_SYSTEM).fieldOf("star_system").forGetter(Planet::system),
|
||||
Codec.BOOL.fieldOf("oxygen").forGetter(Planet::oxygen),
|
||||
Codec.FLOAT.fieldOf("gravity").forGetter(Planet::gravity)
|
||||
Codec.FLOAT.fieldOf("gravity").forGetter(Planet::gravity),
|
||||
ResourceKey.codec(ModRegistries.PLANET).optionalFieldOf("parent_planet").forGetter(Planet::parentPlanet)
|
||||
|
||||
).apply(inst, Planet::new));
|
||||
}
|
||||
|
||||
@@ -6,15 +6,19 @@ import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.xevianlight.aphelion.Aphelion;
|
||||
import net.xevianlight.aphelion.util.registries.ModRegistries;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class PlanetCache {
|
||||
|
||||
public static final Map<ResourceLocation, Planet> PLANETS = new HashMap<>();
|
||||
public static final Map<ResourceKey<Level>, ResourceLocation> PLANET_BY_DIMENSION = new HashMap<>();
|
||||
public static final Map<ResourceLocation, Planet> PLANET_BY_ORBIT = new HashMap<>();
|
||||
|
||||
public static final Planet DEFAULT = new Planet(
|
||||
ResourceKey.create(Registries.DIMENSION, ResourceLocation.withDefaultNamespace("overworld")),
|
||||
@@ -22,7 +26,8 @@ public final class PlanetCache {
|
||||
1,
|
||||
ResourceKey.create(ModRegistries.STAR_SYSTEM, Aphelion.id("sol")),
|
||||
true,
|
||||
1
|
||||
1,
|
||||
Optional.empty()
|
||||
);
|
||||
|
||||
public static void registerPlanets(Map<ResourceLocation, Planet> planets) {
|
||||
@@ -34,6 +39,7 @@ public final class PlanetCache {
|
||||
planets.forEach((planetId, planet) -> {
|
||||
var dim = planet.dimension();
|
||||
var prev = PLANET_BY_DIMENSION.put(dim, planetId);
|
||||
PLANET_BY_ORBIT.put(planet.orbit().location(), planet);
|
||||
if (prev != null) {
|
||||
Aphelion.LOGGER.warn(
|
||||
"Dimension {} is claimed by multiple planets: {} and {}. Keeping latest: {}",
|
||||
@@ -61,8 +67,27 @@ public final class PlanetCache {
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public static @NotNull Planet getByOrbitOrDefault(ResourceLocation id) {
|
||||
return PLANETS.values().stream()
|
||||
.filter(planet -> planet.orbit().location().equals(id))
|
||||
.findFirst()
|
||||
.orElse(DEFAULT);
|
||||
}
|
||||
|
||||
public static Planet getByDimensionOrNull(ResourceKey<Level> dimension) {
|
||||
ResourceLocation planetId = PLANET_BY_DIMENSION.get(dimension);
|
||||
return planetId == null ? null : PLANETS.get(planetId);
|
||||
}
|
||||
|
||||
public static @NotNull List<Planet> getSatellites(ResourceLocation id) {
|
||||
return PLANETS.values().stream()
|
||||
.filter(planet -> planet.parentPlanet()
|
||||
.map(key -> key.location().equals(id))
|
||||
.orElse(false))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public static @NotNull List<Planet> getSatellites(ResourceKey<Planet> key) {
|
||||
return getSatellites(key.location());
|
||||
}
|
||||
}
|
||||
|
||||
8
src/main/resources/data/aphelion/planet/earth.json
Normal file
8
src/main/resources/data/aphelion/planet/earth.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"dimension": "minecraft:overworld",
|
||||
"orbit": "aphelion:orbit/earth",
|
||||
"orbit_distance": 1,
|
||||
"star_system": "aphelion:sol",
|
||||
"gravity": 1,
|
||||
"oxygen": false
|
||||
}
|
||||
Reference in New Issue
Block a user