1313import net .minecraft .commands .execution .ExecutionContext ;
1414import net .minecraft .commands .functions .CommandFunction ;
1515import net .minecraft .commands .functions .InstantiatedFunction ;
16+ import net .minecraft .core .Holder ;
17+ import net .minecraft .core .HolderGetter ;
18+ import net .minecraft .core .registries .Registries ;
1619import net .minecraft .gametest .framework .*;
20+ import net .minecraft .network .chat .Component ;
21+ import net .minecraft .resources .ResourceKey ;
1722import net .minecraft .resources .ResourceLocation ;
18- import net .minecraft .server .level .ServerLevel ;
23+ import net .minecraft .world .level .block . Rotation ;
1924import net .minecraft .world .phys .Vec3 ;
2025
2126import java .util .*;
22- import java .util .function .Consumer ;
2327import java .util .regex .Matcher ;
2428import java .util .regex .Pattern ;
2529
26- public class PackTestFunction {
30+ public record PackTestFunction ( Map < String , String > directives , List < Step > steps , int permissionLevel ) {
2731 private static final Pattern DIRECTIVE_PATTERN = Pattern .compile ("^#\\ s*@(\\ w+)(?:\\ s+(.+))?$" );
28- private static final String DEFAULT_BATCH = "packtestBatch" ;
29- private static final String DEFAULT_TEMPLATE = "packtest:empty" ;
30- private final ResourceLocation id ;
31- private final Map <String , String > directives ;
32- private final List <Step > steps ;
3332
34- public PackTestFunction (ResourceLocation id , Map <String , String > directives , List <Step > steps ) {
35- this .id = id ;
36- this .directives = directives ;
37- this .steps = steps ;
33+ public void run (GameTestHelper helper ) {
34+ CommandSourceStack source = helper .getLevel ().getServer ().createCommandSourceStack ()
35+ .withPosition (helper .absoluteVec (Vec3 .ZERO ))
36+ .withPermission (this .permissionLevel )
37+ .withSuppressedOutput ();
38+ ((PackTestSourceStack ) source ).packtest$setHelper (helper );
39+
40+ Vec3 dummyPos = this .getDummyPos (source ).orElse (null );
41+ Dummy dummy ;
42+ if (dummyPos != null ) {
43+ try {
44+ dummy = Dummy .createRandom (helper .getLevel ().getServer (), helper .getLevel ().dimension (), dummyPos );
45+ dummy .setOnGround (true ); // little hack because we know the dummy will be on the ground
46+ source = source .withEntity (dummy );
47+ } catch (IllegalArgumentException e ) {
48+ throw new GameTestAssertException (Component .literal ("Failed to initialize test with dummy" ), 0 );
49+ }
50+ }
51+
52+ ChatListener chatListener = new ChatListener ();
53+ ((PackTestInfo )((PackTestHelper )helper ).packtest$getInfo ()).packtest$setChatListener (chatListener );
54+ helper .onEachTick (chatListener ::reset );
55+
56+ CommandDispatcher <CommandSourceStack > dispatcher = helper .getLevel ().getServer ().getCommands ().getDispatcher ();
57+ GameTestSequence sequence = helper .startSequence ();
58+ for (Step step : this .steps ) {
59+ step .register (sequence , dispatcher , source );
60+ }
61+ sequence .thenSucceed ();
3862 }
3963
40- public static PackTestFunction fromLines (ResourceLocation id , CommandDispatcher < CommandSourceStack > dispatcher , List <String > lines ) {
64+ public static PackTestFunction fromLines (List <String > lines , int permissionLevel ) {
4165 HashMap <String , String > directives = new HashMap <>();
4266 for (String line : lines ) {
4367 if (!line .startsWith ("#" )) {
@@ -54,30 +78,12 @@ public static PackTestFunction fromLines(ResourceLocation id, CommandDispatcher<
5478 List <Step > steps = new ArrayList <>();
5579 for (int i = 0 ; i < lines .size (); i += 1 ) {
5680 String line = lines .get (i ).stripLeading ();
57- if (line .startsWith ("await delay " )) {
58- steps .add (new IdleStep (line .substring ("await delay " .length ()), i + 1 ));
59- } else if (!line .startsWith ("#" ) && !line .isEmpty ()) {
60- steps .add (new CommandStep (lines .get (i ), i + 1 , dispatcher ));
81+ if (!line .startsWith ("#" ) && !line .isEmpty ()) {
82+ steps .add (new Step (lines .get (i ), i + 1 ));
6183 }
6284 }
6385
64- return new PackTestFunction (id , directives , steps );
65- }
66-
67- private String getTestName () {
68- return this .id .toLanguageKey ();
69- }
70-
71- private String getTemplateName () {
72- return this .directives .getOrDefault ("template" , DEFAULT_TEMPLATE );
73- }
74-
75- private String getBatchName () {
76- return this .directives .getOrDefault ("batch" , DEFAULT_BATCH );
77- }
78-
79- private int getTimeout () {
80- return Optional .ofNullable (this .directives .get ("timeout" )).map (Integer ::parseInt ).orElse (100 );
86+ return new PackTestFunction (directives , steps , permissionLevel );
8187 }
8288
8389 private Optional <Vec3 > getDummyPos (CommandSourceStack source ) {
@@ -95,97 +101,41 @@ private Optional<Vec3> getDummyPos(CommandSourceStack source) {
95101 }
96102 }
97103
98- private boolean isRequired () {
99- return Optional .ofNullable (this .directives .get ("optional" )).map (s -> !Boolean .parseBoolean (s )).orElse (true );
100- }
101-
102- private boolean needsSkyAccess () {
103- return Optional .ofNullable (this .directives .get ("skyaccess" )).map (Boolean ::parseBoolean ).orElse (false );
104+ public TestData <Holder <TestEnvironmentDefinition >> getTestData (HolderGetter .Provider registries ) {
105+ var environments = registries .lookup (Registries .TEST_ENVIRONMENT ).orElseThrow ();
106+ ResourceLocation environmentId = Optional .ofNullable (this .directives .get ("environment" )).map (ResourceLocation ::parse ).orElse (GameTestEnvironments .DEFAULT_KEY .location ());
107+ Holder <TestEnvironmentDefinition > environment = environments .getOrThrow (ResourceKey .create (Registries .TEST_ENVIRONMENT , environmentId ));
108+ ResourceLocation structure = Optional .ofNullable (this .directives .get ("template" )).map (ResourceLocation ::parse ).orElse (ResourceLocation .withDefaultNamespace ("empty" ));
109+ int maxTicks = Optional .ofNullable (this .directives .get ("timeout" )).map (Integer ::parseInt ).orElse (100 );
110+ boolean required = Optional .ofNullable (this .directives .get ("optional" )).map (s -> !Boolean .parseBoolean (s )).orElse (true );
111+ boolean skyAccess = Optional .ofNullable (this .directives .get ("skyaccess" )).map (Boolean ::parseBoolean ).orElse (false );
112+ return new TestData <>(environment , structure , maxTicks , 0 , required , Rotation .NONE , false , 1 , 1 , skyAccess );
104113 }
105114
106- public void registerBatchHook (int permissionLevel , Map <String , Consumer <ServerLevel >> map , String type ) {
107- String command = this .directives .get (type + "batch" );
108- if (command == null ) {
109- return ;
110- }
111- String batchName = this .getBatchName ();
112- Consumer <ServerLevel > oldBefore = map .putIfAbsent (batchName , (level ) -> {
113- CommandSourceStack source = level .getServer ().createCommandSourceStack ()
114- .withPermission (permissionLevel );
115- level .getServer ().getCommands ().performPrefixedCommand (source , command );
116- });
117- if (oldBefore != null ) {
118- PackTest .LOGGER .error ("Only one @{}batch is allowed per batch. Batch '{}' has more than one!" , type , batchName );
119- }
120- }
121-
122- public TestFunction toTestFunction (int permissionLevel ) {
123- return new TestFunction (
124- this .getBatchName (),
125- this .getTestName (),
126- this .getTemplateName (),
127- StructureUtils .getRotationForRotationSteps (0 ),
128- this .getTimeout (),
129- 0L ,
130- this .isRequired (),
131- false ,
132- 1 ,
133- 1 ,
134- this .needsSkyAccess (),
135- createTestBody (permissionLevel ));
136- }
137-
138- private Consumer <GameTestHelper > createTestBody (int permissionLevel ) {
139- return (helper ) -> {
140- CommandSourceStack source = helper .getLevel ().getServer ().createCommandSourceStack ()
141- .withPosition (helper .absoluteVec (Vec3 .ZERO ))
142- .withPermission (permissionLevel )
143- .withSuppressedOutput ();
144- ((PackTestSourceStack ) source ).packtest$setHelper (helper );
145-
146- Vec3 dummyPos = this .getDummyPos (source ).orElse (null );
147- Dummy dummy ;
148- if (dummyPos != null ) {
115+ public record Step (String line , int lineNumber ) {
116+ public void register (GameTestSequence sequence , CommandDispatcher <CommandSourceStack > dispatcher , CommandSourceStack source ) {
117+ if (this .line .startsWith ("await delay " )) {
149118 try {
150- dummy = Dummy . createRandom ( helper . getLevel (). getServer (), helper . getLevel (). dimension (), dummyPos );
151- dummy . setOnGround ( true ); // little hack because we know the dummy will be on the ground
152- source = source . withEntity ( dummy );
153- } catch (IllegalArgumentException e ) {
154- throw new GameTestAssertException ( "Failed to initialize test with dummy" );
119+ String timeArgument = line . substring ( "await delay " . length () );
120+ int ticks = TimeArgument . time (). parse ( new StringReader ( timeArgument ));
121+ (( PackTestSequence ) sequence ). packtest$thenIdle ( ticks , lineNumber , timeArgument );
122+ } catch (CommandSyntaxException e ) {
123+ throw new LineNumberException ( Component . literal ( "Whilst parsing command: " + e . getMessage ()), 0 , lineNumber );
155124 }
125+ return ;
156126 }
157-
158- ChatListener chatListener = new ChatListener ();
159- ((PackTestInfo )((PackTestHelper )helper ).packtest$getInfo ()).packtest$setChatListener (chatListener );
160- helper .onEachTick (chatListener ::reset );
161-
162- GameTestSequence sequence = helper .startSequence ();
163- for (Step step : this .steps ) {
164- step .register (sequence , source );
165- }
166- sequence .thenSucceed ();
167- };
168- }
169-
170- public interface Step {
171- void register (GameTestSequence sequence , CommandSourceStack source );
172- }
173-
174- public record CommandStep (String line , int lineNumber , CommandDispatcher <CommandSourceStack > dispatcher ) implements Step {
175- @ Override
176- public void register (GameTestSequence sequence , CommandSourceStack source ) {
177127 try {
178128 ResourceLocation id = ResourceLocation .fromNamespaceAndPath ("packtest" , "internal" );
179- CommandFunction <CommandSourceStack > function = CommandFunction .fromLines (id , this . dispatcher , source , List .of (this .line ));
180- InstantiatedFunction <CommandSourceStack > instantiated = function .instantiate (null , this . dispatcher );
129+ CommandFunction <CommandSourceStack > function = CommandFunction .fromLines (id , dispatcher , source , List .of (this .line ));
130+ InstantiatedFunction <CommandSourceStack > instantiated = function .instantiate (null , dispatcher );
181131 Runnable runCommands = () -> {
182132 try {
183133 Commands .executeCommandInContext (
184134 source ,
185135 e -> ExecutionContext .queueInitialFunctionCall (e , instantiated , source , CommandResultCallback .EMPTY )
186136 );
187137 } catch (GameTestAssertException e ) {
188- throw new LineNumberException (e . getMessage (), lineNumber );
138+ throw new LineNumberException ((( PackTestAssertException ) e ). packtest$ getMessage(), (( PackTestAssertException ) e ). packtest$getTick (), lineNumber );
189139 }
190140 };
191141 if (line .stripLeading ().startsWith ("await " )) {
@@ -198,22 +148,10 @@ public void register(GameTestSequence sequence, CommandSourceStack source) {
198148 if (message .equals ("Line continuation at end of file" )) {
199149 message = "Line continuation is not supported in tests" ;
200150 }
201- throw new LineNumberException ("Whilst parsing command: " + message , lineNumber );
151+ throw new LineNumberException (Component . literal ( "Whilst parsing command: " + message ), 0 , lineNumber );
202152 } catch (FunctionInstantiationException e ) {
203153 String message = e .messageComponent ().getString ();
204- throw new LineNumberException ("Whilst instantiating command: " + message , lineNumber );
205- }
206- }
207- }
208-
209- public record IdleStep (String argument , int lineNumber ) implements Step {
210- @ Override
211- public void register (GameTestSequence sequence , CommandSourceStack source ) {
212- try {
213- int ticks = TimeArgument .time ().parse (new StringReader (argument ));
214- ((PackTestSequence )sequence ).packtest$thenIdle (ticks , lineNumber , argument );
215- } catch (CommandSyntaxException e ) {
216- throw new LineNumberException ("Whilst parsing command: " + e .getMessage (), lineNumber );
154+ throw new LineNumberException (Component .literal ("Whilst instantiating command: " + message ), 0 , lineNumber );
217155 }
218156 }
219157 }
0 commit comments