Skip to content

Commit 66e2e19

Browse files
authored
Merge branch 'ryanhcode:main' into main
2 parents 6d05ba1 + 6966d29 commit 66e2e19

65 files changed

Lines changed: 1091 additions & 435 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎CONTRIBUTING.md‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
When submitting a pull request to Sable, you are giving [RyanHCode](https://github.com/ryanhcode) the right to license
44
your contributions under the [Polyform Shield License (Version 1.0.0)](LICENSE.md), and you irrevocably permit a potential
5-
future re-licensing of Sable, containing your contributions, under the [MIT license](https://opensource.org/license/mit).
5+
future re-licensing of Sable by [RyanHCode](https://github.com/ryanhcode), containing your contributions, under the
6+
[MIT license](https://opensource.org/license/mit).
67

7-
The submitted code of your PR must be your own, original work, that you have the right to contribute.
8+
The submitted code of your PR must be your own, original work, that you have the right to contribute to Sable.

‎changelog.md‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
1-
- Fix a crash with sub-level splitting
2-
- Fix and add recovery for an issue with sub-levels not loading in because their bounds got set to [0,0,0,0,0,0]
1+
- Fix an issue where assembling massless Create contraptions would crash the server

‎common/src/main/java/dev/ryanhcode/sable/SableCommonEvents.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import dev.ryanhcode.sable.physics.chunk.VoxelNeighborhoodState;
88
import dev.ryanhcode.sable.physics.config.FloatingBlockMaterialDataHandler;
99
import dev.ryanhcode.sable.physics.config.block_properties.PhysicsBlockPropertiesDefinitionLoader;
10+
import dev.ryanhcode.sable.physics.config.dimension_physics.DimensionPhysicsData;
1011
import dev.ryanhcode.sable.physics.floating_block.FloatingBlockController;
1112
import dev.ryanhcode.sable.sublevel.ServerSubLevel;
1213
import dev.ryanhcode.sable.sublevel.SubLevel;
@@ -93,6 +94,7 @@ public static void handleBlockChange(final ServerLevel level, final LevelChunk c
9394

9495
public static void syncDataPacket(final VeilPacketManager.PacketSink sink) {
9596
sink.sendPacket(PhysicsBlockPropertiesDefinitionLoader.INSTANCE.getDefinitions().stream().map(ClientboundPhysicsPropertyPacket::new).toArray(CustomPacketPayload[]::new));
97+
sink.sendPacket(DimensionPhysicsData.compilePacket());
9698
sink.sendPacket(FloatingBlockMaterialDataHandler.allMaterials.entrySet().stream().map(e -> new ClientboundFloatingBlockMaterialPacket(e.getKey(), e.getValue())).toArray(CustomPacketPayload[]::new));
9799
}
98100
}

‎common/src/main/java/dev/ryanhcode/sable/SableConfig.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ public final class SableConfig {
1818
public static final ModConfigSpec.IntValue SUB_LEVEL_PUNCH_COOLDOWN_TICKS;
1919
public static final ModConfigSpec.BooleanValue DISABLE_UDP_PIPELINE;
2020
public static final ModConfigSpec.BooleanValue ATTEMPT_UDP_NETWORKING;
21-
public static final ModConfigSpec.BooleanValue VERBOSE_SERIALIZATION_LOGGING;
2221
public static final ModConfigSpec.BooleanValue SUB_LEVEL_SAVING_LOG_MESSAGE;
22+
public static final ModConfigSpec.BooleanValue VERBOSE_SERIALIZATION_LOGGING;
2323

2424
static {
2525
final ModConfigSpec.Builder builder = new ModConfigSpec.Builder();
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package dev.ryanhcode.sable;
2+
3+
import net.neoforged.neoforge.common.ModConfigSpec;
4+
5+
public final class SableServerConfig {
6+
7+
public static final ModConfigSpec SPEC;
8+
9+
public static final ModConfigSpec.IntValue SUB_LEVEL_SUBSTEPS_PER_TICK;
10+
public static final ModConfigSpec.BooleanValue SUB_LEVEL_STORAGE_PRUNING;
11+
12+
static {
13+
final ModConfigSpec.Builder builder = new ModConfigSpec.Builder();
14+
15+
SUB_LEVEL_SUBSTEPS_PER_TICK = builder
16+
.comment("How many times the physics simulation is stepped in every second. Higher values will be significantly more performance intensive, but will have higher accuracy.")
17+
.defineInRange("sub_level_substeps_per_tick", 2, 1, 10);
18+
19+
SUB_LEVEL_STORAGE_PRUNING = builder
20+
.comment("Prunes and deletes empty sub-level storage files. Experimental.")
21+
.define("sub_level_storage_pruning", false);
22+
23+
SPEC = builder.build();
24+
}
25+
}

‎common/src/main/java/dev/ryanhcode/sable/api/command/SubLevelArgumentType.java‎

Lines changed: 79 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,15 @@
99
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
1010
import com.mojang.brigadier.suggestion.Suggestions;
1111
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
12-
import dev.ryanhcode.sable.command.argument.SubLevelSelector;
1312
import dev.ryanhcode.sable.command.argument.SubLevelSelectorModifierType;
1413
import dev.ryanhcode.sable.command.argument.SubLevelSelectorType;
14+
import dev.ryanhcode.sable.command.argument.SubLevelSuggestionProvider;
15+
import dev.ryanhcode.sable.command.argument.selector.SubLevelTarget;
16+
import dev.ryanhcode.sable.command.argument.selector.SubLevelTargetNone;
17+
import dev.ryanhcode.sable.command.argument.selector.SubLevelTargetSelector;
18+
import dev.ryanhcode.sable.command.argument.selector.SubLevelTargetUUID;
1519
import dev.ryanhcode.sable.sublevel.ServerSubLevel;
20+
import dev.ryanhcode.sable.sublevel.SubLevel;
1621
import it.unimi.dsi.fastutil.Pair;
1722
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
1823
import it.unimi.dsi.fastutil.objects.ObjectList;
@@ -24,26 +29,25 @@
2429
import org.jetbrains.annotations.NotNull;
2530
import org.jetbrains.annotations.Nullable;
2631

27-
import java.util.ArrayList;
28-
import java.util.Arrays;
29-
import java.util.Collection;
30-
import java.util.List;
32+
import java.util.*;
3133
import java.util.concurrent.CompletableFuture;
3234
import java.util.function.Function;
3335

34-
public class SubLevelArgumentType implements ArgumentType<SubLevelSelector> {
36+
public class SubLevelArgumentType implements ArgumentType<SubLevelTarget> {
3537

36-
public static final Function<SuggestionsBuilder, CompletableFuture<Suggestions>> NO_SUGGESTIONS = SuggestionsBuilder::buildFuture;
37-
private static final SimpleCommandExceptionType ERROR_SINGLE_SUB_LEVEL_REQUIRED =
38+
public static final Function<SuggestionsBuilder, SuggestionsBuilder> NO_SUGGESTIONS = b -> b;
39+
public static final SimpleCommandExceptionType ERROR_SINGLE_SUB_LEVEL_REQUIRED =
3840
new SimpleCommandExceptionType(Component.translatable("argument.sable.single_sub_level_required"));
39-
private static final SimpleCommandExceptionType ERROR_INVALID_SUBLEVEL =
40-
new SimpleCommandExceptionType(Component.translatable("argument.sable.sub_level.invalid"));
41-
private static final SimpleCommandExceptionType UNEXPECTED_END_OF_INPUT =
41+
public static final SimpleCommandExceptionType ERROR_INVALID_SELECTOR =
42+
new SimpleCommandExceptionType(Component.translatable("argument.sable.invalid_selector"));
43+
public static final SimpleCommandExceptionType ERROR_UNEXPECTED_END_OF_INPUT =
4244
new SimpleCommandExceptionType(Component.translatable("argument.sable.unexpected_end_of_input"));
45+
public static final SimpleCommandExceptionType ERROR_INVALID_UUID = new SimpleCommandExceptionType(Component.translatable("argument.sable.invalid_uuid"));
46+
public static final SimpleCommandExceptionType ERROR_CANNOT_FIND_SUB_LEVEL = new SimpleCommandExceptionType(Component.translatable("argument.sable.cannot_find_sub_level"));
4347
private static final String STATIC_WORLD = "static_world";
4448
private static final Collection<String> EXAMPLES = Arrays.stream(SubLevelSelectorType.values())
4549
.map(type -> "@" + type.getChar()).toList();
46-
private static Function<SuggestionsBuilder, CompletableFuture<Suggestions>> suggestions = NO_SUGGESTIONS;
50+
private static Function<SuggestionsBuilder, SuggestionsBuilder> SELECTOR_SUGGESTIONS = NO_SUGGESTIONS;
4751
private final boolean allowStaticLevel;
4852
private final boolean allowMultiple;
4953

@@ -53,11 +57,11 @@ public SubLevelArgumentType(final boolean allowStaticLevel, final boolean allowM
5357
}
5458

5559
public static Collection<ServerSubLevel> getSubLevels(final CommandContext<CommandSourceStack> ctx, final String name) throws CommandSyntaxException {
56-
return ctx.getArgument(name, SubLevelSelector.class).getSubLevels(ctx.getSource());
60+
return ctx.getArgument(name, SubLevelTarget.class).getSubLevels(ctx.getSource());
5761
}
5862

5963
public static ServerSubLevel getSingleSubLevel(final CommandContext<CommandSourceStack> ctx, final String name) throws CommandSyntaxException {
60-
final Collection<ServerSubLevel> subLevels = ctx.getArgument(name, SubLevelSelector.class).getSubLevels(ctx.getSource());
64+
final Collection<ServerSubLevel> subLevels = ctx.getArgument(name, SubLevelTarget.class).getSubLevels(ctx.getSource());
6165
if (subLevels.size() > 1) {
6266
throw ERROR_SINGLE_SUB_LEVEL_REQUIRED.create();
6367
}
@@ -83,7 +87,7 @@ public static SubLevelArgumentType subLevelsOrLevel() {
8387

8488
private static @NotNull List<Pair<SubLevelSelectorModifierType, SubLevelSelectorModifierType.Modifier>> parseSelectorArguments(final StringReader reader) throws CommandSyntaxException {
8589
final List<Pair<SubLevelSelectorModifierType, SubLevelSelectorModifierType.Modifier>> modifiers = new ObjectArrayList<>();
86-
setSuggestions(reader, "[");
90+
setSelectorSuggestions(reader, "[");
8791

8892
final List<Pair<String, @Nullable Message>> permittedPreEntryToken = new ArrayList<>(SubLevelSelectorModifierType.getAllNamesWithTooltip()
8993
.stream().map(s -> Pair.of(s.first() + "=", s.second())).toList());
@@ -93,28 +97,28 @@ public static SubLevelArgumentType subLevelsOrLevel() {
9397
if (reader.canRead() && reader.peek() == '[') {
9498
reader.skip();
9599

96-
setSuggestionsWithTooltip(reader, permittedPreEntryToken);
100+
setSelectorSuggestionsWithTooltip(reader, permittedPreEntryToken);
97101
while (reader.canRead() && reader.peek() != ']') {
98102
if (reader.peek() == ',') {
99103
reader.skip();
100104
}
101-
setSuggestionsWithTooltip(reader, permittedPreEntryToken);
105+
setSelectorSuggestionsWithTooltip(reader, permittedPreEntryToken);
102106

103107
final String propertyName = readUntilEndOrCharacter(reader, '=');
104108

105109
if (!reader.canRead() || reader.peek() != '=') {
106-
throw UNEXPECTED_END_OF_INPUT.createWithContext(reader);
110+
throw ERROR_UNEXPECTED_END_OF_INPUT.createWithContext(reader);
107111
}
108112
reader.skip();
109113

110114
final SubLevelSelectorModifierType modifierType = SubLevelSelectorModifierType.getModifier(propertyName, reader);
111115
if (modifierType == null) {
112-
throw UNEXPECTED_END_OF_INPUT.createWithContext(reader);
116+
throw ERROR_UNEXPECTED_END_OF_INPUT.createWithContext(reader);
113117
}
114118
final SubLevelSelectorModifierType.Modifier modifier = modifierType.getParser().parse(reader);
115119
modifiers.add(Pair.of(modifierType, modifier));
116120

117-
setSuggestionsWithTooltip(reader, permittedPreEntryToken);
121+
setSelectorSuggestionsWithTooltip(reader, permittedPreEntryToken);
118122
if (isFirstEntry) {
119123
permittedPreEntryToken.add(Pair.of(",", null));
120124
isFirstEntry = false;
@@ -124,32 +128,33 @@ public static SubLevelArgumentType subLevelsOrLevel() {
124128
if (reader.canRead() && reader.peek() == ']') {
125129
reader.skip();
126130
} else {
127-
throw UNEXPECTED_END_OF_INPUT.createWithContext(reader);
131+
throw ERROR_UNEXPECTED_END_OF_INPUT.createWithContext(reader);
128132
}
129133
}
130134

131135
return modifiers;
132136
}
133137

134-
public static void setSuggestions(final StringReader reader, final String... suggested) {
135-
setSuggestions(reader, Arrays.asList(suggested));
138+
public static void setSelectorSuggestions(final StringReader reader, final String... suggested) {
139+
setSelectorSuggestions(reader, Arrays.asList(suggested));
136140
}
137141

138-
public static void setSuggestions(final StringReader reader, final List<String> suggested) {
139-
setSuggestionsWithTooltip(reader, suggested.stream().map(s -> Pair.of(s, (Message) null)).toList());
142+
public static void setSelectorSuggestions(final StringReader reader, final List<String> suggested) {
143+
setSelectorSuggestionsWithTooltip(reader, suggested.stream().map(s -> Pair.of(s, (Message) null)).toList());
140144
}
141145

142146
@SafeVarargs
143-
public static void setSuggestionsWithTooltip(final StringReader reader, final Pair<String, @Nullable Message>... suggested) {
144-
setSuggestionsWithTooltip(reader, Arrays.asList(suggested));
147+
public static void setSelectorSuggestionsWithTooltip(final StringReader reader, final Pair<String, @Nullable Message>... suggested) {
148+
setSelectorSuggestionsWithTooltip(reader, Arrays.asList(suggested));
145149
}
146150

147-
public static void setSuggestionsWithTooltip(final StringReader reader, final List<Pair<String, @Nullable Message>> suggested) {
151+
public static void setSelectorSuggestionsWithTooltip(final StringReader reader, final List<Pair<String, @Nullable Message>> suggested) {
148152
final int cursor = reader.getCursor();
149-
suggestions = builder -> {
153+
SELECTOR_SUGGESTIONS = builder -> {
150154
final SuggestionsBuilder nextSuggestion = builder.createOffset(cursor);
155+
final String input = builder.getInput().substring(cursor);
151156
for (final Pair<String, @Nullable Message> suggestion : suggested) {
152-
if (!suggestion.first().startsWith(builder.getInput().substring(cursor))) {
157+
if (!suggestion.first().startsWith(input)) {
153158
continue;
154159
}
155160
if (suggestion.second() != null) {
@@ -158,7 +163,7 @@ public static void setSuggestionsWithTooltip(final StringReader reader, final Li
158163
nextSuggestion.suggest(suggestion.first());
159164
}
160165
}
161-
return nextSuggestion.buildFuture();
166+
return nextSuggestion;
162167
};
163168
}
164169

@@ -168,49 +173,54 @@ public static String readUntilEndOrCharacter(final StringReader reader, final ch
168173
builder.append(reader.read());
169174
}
170175
if (builder.isEmpty()) {
171-
throw UNEXPECTED_END_OF_INPUT.create();
176+
throw ERROR_UNEXPECTED_END_OF_INPUT.create();
172177
}
173178
return builder.toString();
174179
}
175180

176181
@Override
177-
public SubLevelSelector parse(final StringReader reader) throws CommandSyntaxException {
182+
public SubLevelTarget parse(final StringReader reader) throws CommandSyntaxException {
178183
final ObjectList<Pair<String, @Nullable Message>> allowedSelectors = new ObjectArrayList<>();
179184
if (this.allowStaticLevel) {
180185
allowedSelectors.add(Pair.of(STATIC_WORLD, Component.translatable("argument.sable.body.static_world")));
181186
}
182187
for (final SubLevelSelectorType selector : SubLevelSelectorType.values()) {
183188
allowedSelectors.add(Pair.of("@" + selector.getChar(), selector.getTooltip()));
184189
}
185-
setSuggestionsWithTooltip(reader, allowedSelectors);
190+
setSelectorSuggestionsWithTooltip(reader, allowedSelectors);
186191

187192
if (this.allowStaticLevel && reader.canRead(STATIC_WORLD.length()) && reader.peek() == STATIC_WORLD.charAt(0)) {
188193
final String staticWorld = reader.readString();
189194

190195
if (!staticWorld.equals(STATIC_WORLD)) {
191-
throw ERROR_INVALID_SUBLEVEL.create();
196+
throw ERROR_INVALID_SELECTOR.create();
192197
}
193198

194-
return new SubLevelSelector(null, new ObjectArrayList<>());
199+
return SubLevelTargetNone.INSTANCE;
195200
}
196201

197202
if (!reader.canRead()) {
198-
throw ERROR_INVALID_SUBLEVEL.create();
203+
throw ERROR_INVALID_SELECTOR.create();
199204
}
200205

201-
final char firstChar = reader.read();
206+
final char firstChar = reader.peek();
202207

203-
if (!reader.canRead() || firstChar != '@') {
204-
throw ERROR_INVALID_SUBLEVEL.create();
208+
if (firstChar == '@') {
209+
reader.skip();
210+
return this.parseSelector(reader);
211+
} else {
212+
return this.parseUUID(reader);
205213
}
214+
}
206215

216+
private SubLevelTarget parseSelector(final StringReader reader) throws CommandSyntaxException {
207217
if (!reader.canRead()) {
208-
throw ERROR_INVALID_SUBLEVEL.create();
218+
throw ERROR_INVALID_SELECTOR.create();
209219
}
210220

211221
final SubLevelSelectorType selectorType = SubLevelSelectorType.of(reader.read());
212222
if (selectorType == null) {
213-
throw ERROR_INVALID_SUBLEVEL.create();
223+
throw ERROR_INVALID_SELECTOR.create();
214224
}
215225

216226
int maximumResults = Integer.MAX_VALUE;
@@ -230,19 +240,41 @@ public SubLevelSelector parse(final StringReader reader) throws CommandSyntaxExc
230240
throw ERROR_SINGLE_SUB_LEVEL_REQUIRED.create();
231241
}
232242

233-
return new SubLevelSelector(selectorType, modifiers);
243+
return new SubLevelTargetSelector(selectorType, modifiers);
244+
}
245+
246+
private SubLevelTarget parseUUID(final StringReader reader) throws CommandSyntaxException {
247+
final String s = reader.readString();
248+
try {
249+
return new SubLevelTargetUUID(UUID.fromString(s));
250+
} catch (final IllegalArgumentException e) {
251+
throw ERROR_INVALID_UUID.createWithContext(reader);
252+
}
234253
}
235254

236255
@Override
237-
public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> pContext, final SuggestionsBuilder builder) {
256+
public <S> CompletableFuture<Suggestions> listSuggestions(final CommandContext<S> pContext, SuggestionsBuilder builder) {
238257
final StringReader stringreader = new StringReader(builder.getInput());
239-
stringreader.setCursor(builder.getStart());
240-
suggestions = NO_SUGGESTIONS;
258+
final int start = builder.getStart();
259+
stringreader.setCursor(start);
260+
SELECTOR_SUGGESTIONS = NO_SUGGESTIONS;
241261
try {
242262
this.parse(stringreader);
243263
} catch (final CommandSyntaxException ignored) {
244264
}
245-
return suggestions.apply(builder);
265+
builder = SELECTOR_SUGGESTIONS.apply(builder);
266+
267+
if (pContext.getSource() instanceof final SubLevelSuggestionProvider suggestionProvider) {
268+
final SubLevel subLevel = suggestionProvider.getSelectedSubLevel();
269+
if (subLevel != null) {
270+
final String uuid = subLevel.getUniqueId().toString();
271+
final String input = builder.getInput().substring(start);
272+
if (uuid.startsWith(input)) {
273+
builder.suggest(uuid);
274+
}
275+
}
276+
}
277+
return builder.buildFuture();
246278
}
247279

248280
@Override

‎common/src/main/java/dev/ryanhcode/sable/api/physics/force/QueuedForceGroup.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public void applyAndRecordPointForce(final Vector3dc point, final Vector3dc forc
2626
this.forceTotal.applyImpulseAtPoint(this.subLevel.getMassTracker(), point, force);
2727
this.recordPointForce(point, force);
2828
}
29+
2930
public void recordPointForce(final Vector3dc point, final Vector3dc force) {
3031
if (!this.subLevel.isTrackingIndividualQueuedForces()) {
3132
return;

‎common/src/main/java/dev/ryanhcode/sable/api/physics/mass/MassData.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public interface MassData {
3434
Vector3dc getCenterOfMass();
3535

3636
default boolean isInvalid() {
37-
return this.getMass() <= 0.0;
37+
return this.getMass() <= 0.0 || this.getCenterOfMass() == null;
3838
}
3939

4040
/**

‎common/src/main/java/dev/ryanhcode/sable/api/sublevel/ServerSubLevelContainer.java‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,11 @@ public Collection<ServerSubLevel> collectForceLoadedSubLevels() {
273273
return subLevels;
274274
}
275275

276+
@ApiStatus.Internal
277+
public Map<ServerSubLevel, Set<SubLevelLoadingTicket<?>>> collectForceLoadTickets() {
278+
return Collections.unmodifiableMap(this.activeTickets);
279+
}
280+
276281
/**
277282
* Loads sub-level tickets
278283
*/

0 commit comments

Comments
 (0)