Skip to content

Commit b6a90ed

Browse files
committed
v0.14.15.5 - Storm Builder
- Added a storm builder, allowing you to easily create and spawn storms Took 1 hour 46 minutes
1 parent fc3b6be commit b6a90ed

5 files changed

Lines changed: 338 additions & 11 deletions

File tree

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,22 @@ Need help? Join the Discord server [here](https://discord.gg/B6YKNVB6pW)!
66

77
## About
88

9-
![pmweatherapi](https://img.shields.io/maven-metadata/v?label=pmweatherapi\&metadataUrl=https://maven.digitalunderworlds.com/snapshots/net/nullved/pmweatherapi/maven-metadata.xml)
9+
![pmweatherapi](https://img.shields.io/maven-metadata/v?label=Latest%20Snapshot&metadataUrl=https://maven.digitalunderworlds.com/snapshots/net/nullved/pmweatherapi/maven-metadata.xml)
1010

1111
**PMWeatherAPI** is an **unofficial** API designed to simplify interacting with [ProtoManly's Weather Mod](https://modrinth.com/mod/protomanlys-weather/) for those who want to create addons.
1212

1313
### Current features:
1414

15-
* Nearby storm detection
16-
* Nearby radar detection
17-
* Radar overlays
15+
* Nearby Storm Detection
16+
* Nearby Radar Detection
17+
* Radar Overlays
18+
* Storm Builder
19+
* Events
1820

1921
> ⚠️ This API is currently experimental due to PMWeather still being in alpha. Bugs should be expected.
2022
> The API will aim to stay updated with PMWeather as closely as possible.
2123
22-
Make sure you only use the API version that matches your PMWeather version (e.g., `0.14.15.0` works with `PMWeather 0.14.15-alpha` but may not work with other versions).
24+
Make sure you only use the API version that matches your PMWeather version (e.g., `0.14.15.X` works with `PMWeather 0.14.15-alpha` but may not work with other versions).
2325

2426
## Adding to Your Project
2527

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ parchment_mappings_version=2024.11.17
1717
mod_id=pmweatherapi
1818
mod_name=PMWeatherAPI
1919
mod_license=GNU GPL 3.0
20-
mod_version=0.14.15.4
20+
mod_version=0.14.15.5
2121
mod_group_id=net.nullved
2222
mod_authors=NullVed
2323
mod_description=An API for interfacing with ProtoManly's Weather Mod

src/main/java/net/nullved/pmweatherapi/command/NearbyRadarsCommand.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313
import net.nullved.pmweatherapi.PMWeatherAPI;
1414
import net.nullved.pmweatherapi.radar.NearbyRadars;
1515

16-
import java.util.ArrayList;
17-
import java.util.List;
1816
import java.util.Set;
1917

2018
public class NearbyRadarsCommand {
@@ -41,7 +39,7 @@ private static int nearbyRadars(CommandContext<CommandSourceStack> ctx) {
4139
radius = ctx.getArgument("radius", Integer.class);
4240
} catch (Exception e) {
4341
radius = 512;
44-
};
42+
}
4543

4644
long startTimeMillis = System.currentTimeMillis();
4745
Set<BlockPos> blocks = NearbyRadars.get(plr.level()).radarsNearBlock(plr.blockPosition(), radius);

src/main/java/net/nullved/pmweatherapi/mixin/StormMixin.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
55
import dev.protomanly.pmweather.weather.Storm;
66
import dev.protomanly.pmweather.weather.Vorticy;
7-
import dev.protomanly.pmweather.weather.WeatherHandlerServer;
8-
import net.minecraft.world.phys.Vec3;
97
import net.neoforged.neoforge.common.NeoForge;
108
import net.nullved.pmweatherapi.event.StormEvent;
119
import net.nullved.pmweatherapi.event.VorticyEvent;
Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
package net.nullved.pmweatherapi.storm;
2+
3+
import dev.protomanly.pmweather.PMWeather;
4+
import dev.protomanly.pmweather.config.ServerConfig;
5+
import dev.protomanly.pmweather.event.GameBusEvents;
6+
import dev.protomanly.pmweather.weather.Storm;
7+
import dev.protomanly.pmweather.weather.WeatherHandler;
8+
import dev.protomanly.pmweather.weather.WeatherHandlerServer;
9+
import net.minecraft.resources.ResourceKey;
10+
import net.minecraft.world.entity.player.Player;
11+
import net.minecraft.world.level.Level;
12+
import net.minecraft.world.phys.Vec3;
13+
14+
/**
15+
* A builder for {@link Storm}s that makes it easy to create and spawn them.
16+
* Create a StormBuilder with any constructor or {@link #atPlayer(Type, Player)}
17+
* <br>
18+
* To spawn the storm in the world, use {@link #buildAndSpawn()}. To only create the storm instance, use {@link #build()}
19+
* @since 0.14.15.5
20+
*/
21+
public class StormBuilder {
22+
private final WeatherHandler weatherHandler;
23+
private final Type type;
24+
private final Vec3 position;
25+
private float risk = 0.5f, rankineFactor = 4.5F, width = 15.0F;
26+
private int windspeed = 0, maxWindspeed = 0, stage = 0, maxStage = 2, energy = 0, coldEnergy = 0, maxColdEnergy = 300, maxWidth = 15;
27+
private Vec3 velocity = Vec3.ZERO;
28+
private boolean visualOnly = false, aimAtAnyPlayer = false;
29+
private Player aimAtPlayer;
30+
31+
/**
32+
* Create a new {@link StormBuilder}
33+
* @param weatherHandler The {@link WeatherHandler} to use
34+
* @param type The {@link Type} of storm
35+
* @param position The {@link Vec3} representing the position of the {@link Storm}
36+
* @since 0.14.15.5
37+
*/
38+
public StormBuilder(WeatherHandler weatherHandler, Type type, Vec3 position) {
39+
this.weatherHandler = weatherHandler;
40+
this.type = type;
41+
this.position = position;
42+
}
43+
44+
/**
45+
* Create a new {@link StormBuilder}
46+
* @param level The {@link Level} to spawn in
47+
* @param type The {@link Type} of storm
48+
* @param position The {@link Vec3} representing the position of the {@link Storm}
49+
* @since 0.14.15.5
50+
*/
51+
public StormBuilder(Level level, Type type, Vec3 position) {
52+
this(GameBusEvents.MANAGERS.get(level.dimension()), type, position);
53+
}
54+
55+
/**
56+
* Create a new {@link StormBuilder}
57+
* @param dimension The {@link ResourceKey} of the dimension to spawn in
58+
* @param type The {@link Type} of storm
59+
* @param position The {@link Vec3} representing the position of the {@link Storm}
60+
* @since 0.14.15.5
61+
*/
62+
public StormBuilder(ResourceKey<Level> dimension, Type type, Vec3 position) {
63+
this(GameBusEvents.MANAGERS.get(dimension), type, position);
64+
}
65+
66+
/**
67+
* Creates a {@link StormBuilder} at a {@link Player}'s dimension and position
68+
* @param type The {@link Type} of storm
69+
* @param player The {@link Player} to grab the dimension and position from
70+
* @return A new {@link StormBuilder}
71+
* @since 0.14.15.5
72+
*/
73+
public static StormBuilder atPlayer(Type type, Player player) {
74+
return new StormBuilder(player.level(), type, player.position());
75+
}
76+
77+
/**
78+
* Aims the {@link Storm} at the given player.
79+
* Overrides {@link #velocity(Vec3)}.
80+
* Overriden by {@link #aimAtAnyPlayer()}
81+
* @param player The {@link Player} to aim the {@link Storm} at
82+
* @return The {@link StormBuilder} instance
83+
* @since 0.14.15.5
84+
*/
85+
public StormBuilder aimAtPlayer(Player player) {
86+
this.aimAtPlayer = player;
87+
return this;
88+
}
89+
90+
/**
91+
* Aims the {@link Storm} at a random player.
92+
* Overrides {@link #velocity(Vec3)} and {@link #aimAtPlayer(Player)}
93+
* @return The {@link StormBuilder} instance
94+
* @since 0.14.15.5
95+
*/
96+
public StormBuilder aimAtAnyPlayer() {
97+
this.aimAtAnyPlayer = true;
98+
return this;
99+
}
100+
101+
/**
102+
* Set the {@link Storm} to be visual only
103+
* @param visualOnly Whether the storm should be visual only
104+
* @return The {@link StormBuilder} instance
105+
* @since 0.14.15.5
106+
*/
107+
public StormBuilder visualOnly(boolean visualOnly) {
108+
this.visualOnly = visualOnly;
109+
return this;
110+
}
111+
112+
/**
113+
* Sets the risk of the {@link Storm}
114+
* @param risk The risk
115+
* @return The {@link StormBuilder} instance
116+
* @since 0.14.15.5
117+
*/
118+
public StormBuilder risk(float risk) {
119+
this.risk = risk;
120+
return this;
121+
}
122+
123+
/**
124+
* Sets the rankine factor of the {@link Storm}
125+
* @param rankineFactor The rankine factor
126+
* @return The {@link StormBuilder} instance
127+
* @since 0.14.15.5
128+
*/
129+
public StormBuilder rankineFactor(float rankineFactor) {
130+
this.rankineFactor = rankineFactor;
131+
return this;
132+
}
133+
134+
/**
135+
* Sets the width of the {@link Storm}
136+
* @param width The width
137+
* @return The {@link StormBuilder} instance
138+
* @since 0.14.15.5
139+
*/
140+
public StormBuilder width(float width) {
141+
this.width = width;
142+
return this;
143+
}
144+
145+
/**
146+
* Sets the max width of the {@link Storm}
147+
* @param maxWidth The max width
148+
* @return The {@link StormBuilder} instance
149+
* @since 0.14.15.5
150+
*/
151+
public StormBuilder maxWidth(int maxWidth) {
152+
this.maxWidth = maxWidth;
153+
return this;
154+
}
155+
156+
/**
157+
* Sets the stage of the {@link Storm}
158+
* @param stage The stage
159+
* @return The {@link StormBuilder} instance
160+
* @since 0.14.15.5
161+
*/
162+
public StormBuilder stage(int stage) {
163+
this.stage = stage;
164+
return this;
165+
}
166+
167+
/**
168+
* Sets the max stage of the {@link Storm}
169+
* @param maxStage The max stage
170+
* @return The {@link StormBuilder} instance
171+
* @since 0.14.15.5
172+
*/
173+
public StormBuilder maxStage(int maxStage) {
174+
this.maxStage = maxStage;
175+
return this;
176+
}
177+
178+
/**
179+
* Sets the energy of the {@link Storm}
180+
* @param energy The energy
181+
* @return The {@link StormBuilder} instance
182+
* @since 0.14.15.5
183+
*/
184+
public StormBuilder energy(int energy) {
185+
this.energy = energy;
186+
return this;
187+
}
188+
189+
/**
190+
* Sets the cold energy of the {@link Storm}
191+
* @param coldEnergy The cold energy
192+
* @return The {@link StormBuilder} instance
193+
* @since 0.14.15.5
194+
*/
195+
public StormBuilder coldEnergy(int coldEnergy) {
196+
this.coldEnergy = coldEnergy;
197+
return this;
198+
}
199+
200+
/**
201+
* Sets the max cold energy of the {@link Storm}
202+
* @param maxColdEnergy The max cold energy
203+
* @return The {@link StormBuilder} instance
204+
* @since 0.14.15.5
205+
*/
206+
public StormBuilder maxColdEnergy(int maxColdEnergy) {
207+
this.maxColdEnergy = maxColdEnergy;
208+
return this;
209+
}
210+
211+
/**
212+
* Sets the windspeed of the {@link Storm}
213+
* @param windspeed The windspeed
214+
* @return The {@link StormBuilder} instance
215+
* @since 0.14.15.5
216+
*/
217+
public StormBuilder windspeed(int windspeed) {
218+
this.windspeed = windspeed;
219+
return this;
220+
}
221+
222+
/**
223+
* Sets the max windspeed of the {@link Storm}
224+
* @param maxWindspeed The max windspeed
225+
* @return The {@link StormBuilder} instance
226+
* @since 0.14.15.5
227+
*/
228+
public StormBuilder maxWindspeed(int maxWindspeed) {
229+
this.maxWindspeed = maxWindspeed;
230+
return this;
231+
}
232+
233+
/**
234+
* Sets the velocity of the {@link Storm}.
235+
* Overriden by {@link #aimAtPlayer(Player)} and {@link #aimAtAnyPlayer()}
236+
* @param velocity The velocity of the storm
237+
* @return The {@link StormBuilder} instance
238+
* @since 0.14.15.5
239+
*/
240+
public StormBuilder velocity(Vec3 velocity) {
241+
this.velocity = velocity;
242+
return this;
243+
}
244+
245+
/**
246+
* Builds the final storm, but does NOT spawn it.
247+
* To spawn in, use {@link #buildAndSpawn()} instead
248+
* @return The built {@link Storm} instance
249+
* @since 0.14.15.5
250+
*/
251+
public Storm build() {
252+
Storm storm = new Storm(weatherHandler, weatherHandler.getWorld(), risk, type.ordinal());
253+
storm.initFirstTime();
254+
storm.visualOnly = visualOnly;
255+
storm.velocity = velocity;
256+
if (aimAtPlayer != null) {
257+
if (storm.stormType != Type.SQUALL.ordinal()) {
258+
Vec3 aimPos = aimAtPlayer.position().add(new Vec3((double)(PMWeather.RANDOM.nextFloat() - 0.5F) * ServerConfig.aimAtPlayerOffset, 0.0F, (double)(PMWeather.RANDOM.nextFloat() - 0.5F) * ServerConfig.aimAtPlayerOffset));
259+
if (storm.position.distanceTo(aimPos) >= ServerConfig.aimAtPlayerOffset) {
260+
Vec3 toward = storm.position.subtract(new Vec3(aimPos.x, storm.position.y, aimPos.z)).multiply(1.0F, 0.0F, 1.0F).normalize();
261+
double speed = PMWeather.RANDOM.nextDouble() * (double)5.0F + (double)1.0F;
262+
storm.velocity = toward.multiply(-speed, 0.0F, -speed);
263+
}
264+
265+
storm.aimedAtPlayer = true;
266+
}
267+
}
268+
if (aimAtAnyPlayer) {
269+
if (storm.stormType != Type.SQUALL.ordinal()) {
270+
Player nearest = storm.level.getNearestPlayer(this.position.x, this.position.y, this.position.z, 4096.0F, false);
271+
if (nearest != null) {
272+
Vec3 aimPos = aimAtPlayer.position().add(new Vec3((double) (PMWeather.RANDOM.nextFloat() - 0.5F) * ServerConfig.aimAtPlayerOffset, 0.0F, (double) (PMWeather.RANDOM.nextFloat() - 0.5F) * ServerConfig.aimAtPlayerOffset));
273+
if (storm.position.distanceTo(aimPos) >= ServerConfig.aimAtPlayerOffset) {
274+
Vec3 toward = storm.position.subtract(new Vec3(aimPos.x, storm.position.y, aimPos.z)).multiply(1.0F, 0.0F, 1.0F).normalize();
275+
double speed = PMWeather.RANDOM.nextDouble() * (double) 5.0F + (double) 1.0F;
276+
storm.velocity = toward.multiply(-speed, 0.0F, -speed);
277+
}
278+
279+
storm.aimedAtPlayer = true;
280+
}
281+
282+
}
283+
}
284+
storm.position = position;
285+
storm.stage = stage;
286+
storm.maxStage = maxStage;
287+
storm.energy = energy;
288+
storm.width = width;
289+
storm.maxWidth = maxWidth;
290+
storm.rankineFactor = rankineFactor;
291+
storm.coldEnergy = coldEnergy;
292+
storm.maxColdEnergy = maxColdEnergy;
293+
storm.windspeed = windspeed;
294+
storm.maxWindspeed = maxWindspeed;
295+
return storm;
296+
}
297+
298+
/**
299+
* Builds the final storm and spawns it.
300+
* To NOT spawn it, use {@link #build()} instead
301+
* @return The built {@link Storm} instance
302+
* @since 0.14.15.5
303+
*/
304+
public Storm buildAndSpawn() {
305+
Storm storm = build();
306+
weatherHandler.addStorm(storm);
307+
if (weatherHandler instanceof WeatherHandlerServer whs) {
308+
whs.syncStormNew(storm);
309+
}
310+
return storm;
311+
}
312+
313+
/**
314+
* An enum with types of {@link Storm}s
315+
* @since 0.14.15.5
316+
*/
317+
public enum Type {
318+
/**
319+
* Represents both supercells and tornados
320+
* @since 0.14.15.5
321+
*/
322+
SUPERCELL,
323+
/**
324+
* Represents squall lines
325+
* @since 0.14.15.5
326+
*/
327+
SQUALL
328+
}
329+
}

0 commit comments

Comments
 (0)