Skip to content

Commit bcfe780

Browse files
committed
FlappyGreg is pretty functional now
1 parent a7f5c59 commit bcfe780

File tree

7 files changed

+506
-4
lines changed

7 files changed

+506
-4
lines changed

src/main/java/gregtech/api/GTValues.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ public static boolean isDeobfEnvironment() {
192192
public static final int FALLBACK = -1;
193193

194194
public static BooleanSupplier FOOLS = () -> {
195-
return true;
195+
return true; // TODO: change back once done testing the maintenance hatch april fools minigame
196196
// String[] yearMonthDay = LocalDate.now().toString().split("-");
197197
// return ConfigHolder.misc.specialEvents && yearMonthDay[1].equals("04") && yearMonthDay[2].equals("01");
198198
};
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package gregtech.api.mui.sync;
2+
3+
import gregtech.api.GTValues;
4+
5+
import net.minecraft.network.PacketBuffer;
6+
7+
import com.cleanroommc.modularui.value.sync.SyncHandler;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
import java.io.IOException;
11+
12+
public class SingleActionSyncHandler extends SyncHandler {
13+
14+
@Nullable
15+
private Runnable clientAction;
16+
@Nullable
17+
private Runnable serverAction;
18+
19+
/**
20+
* Set the action to run client side.
21+
*/
22+
public void clientAction(@Nullable Runnable clientAction) {
23+
if (!GTValues.isClientSide()) return;
24+
this.clientAction = clientAction;
25+
}
26+
27+
/**
28+
* Set the action to run server side.
29+
*/
30+
public void serverAction(@Nullable Runnable serverAction) {
31+
if (GTValues.isClientSide()) return;
32+
this.serverAction = serverAction;
33+
}
34+
35+
@Override
36+
public void readOnClient(int id, PacketBuffer buf) throws IOException {
37+
if (clientAction != null) {
38+
clientAction.run();
39+
}
40+
}
41+
42+
@Override
43+
public void readOnServer(int id, PacketBuffer buf) throws IOException {
44+
if (serverAction != null) {
45+
serverAction.run();
46+
}
47+
}
48+
49+
/**
50+
* Run the client action immediately if client-side, or tell the client to run the action if server-side.
51+
*/
52+
public void notifyClient() {
53+
if (getSyncManager().isClient()) {
54+
if (clientAction != null) {
55+
clientAction.run();
56+
}
57+
} else {
58+
syncToClient(0);
59+
}
60+
}
61+
62+
/**
63+
* Run the server action immediately if server-side, or tell the server to run the action if client-side.
64+
*/
65+
public void notifyServer() {
66+
if (getSyncManager().isClient()) {
67+
syncToServer(0);
68+
} else {
69+
if (serverAction != null) {
70+
serverAction.run();
71+
}
72+
}
73+
}
74+
}
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
package gregtech.api.mui.widget;
2+
3+
import gregtech.api.GTValues;
4+
import gregtech.api.mui.GTGuiTextures;
5+
import gregtech.api.mui.sync.SingleActionSyncHandler;
6+
import gregtech.api.util.Rectangle;
7+
import gregtech.client.utils.RenderUtil;
8+
9+
import net.minecraft.client.renderer.GlStateManager;
10+
import net.minecraft.util.text.TextFormatting;
11+
import net.minecraftforge.fml.relauncher.Side;
12+
import net.minecraftforge.fml.relauncher.SideOnly;
13+
14+
import com.cleanroommc.modularui.api.drawable.IKey;
15+
import com.cleanroommc.modularui.api.widget.Interactable;
16+
import com.cleanroommc.modularui.drawable.GuiDraw;
17+
import com.cleanroommc.modularui.screen.viewport.ModularGuiContext;
18+
import com.cleanroommc.modularui.theme.WidgetTheme;
19+
import com.cleanroommc.modularui.theme.WidgetThemeEntry;
20+
import com.cleanroommc.modularui.utils.Color;
21+
import com.cleanroommc.modularui.value.sync.SyncHandler;
22+
import com.cleanroommc.modularui.widget.Widget;
23+
import com.cleanroommc.modularui.widget.sizer.Area;
24+
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
25+
import org.jetbrains.annotations.NotNull;
26+
import org.jetbrains.annotations.Nullable;
27+
import org.lwjgl.opengl.GL11;
28+
29+
import java.util.List;
30+
31+
public class FlappyGreg extends Widget<FlappyGreg> implements Interactable {
32+
33+
protected static final int BACKGROUND_COLOR = Color.BLACK.main;
34+
protected static final float WIN_DISTANCE = 25.0f;
35+
36+
protected static final float CLICK_IMPULSE = 1.75f;
37+
protected static final float TERMINAL_VELOCITY = 2.0f;
38+
protected static final float GRAVITY = 0.25f;
39+
40+
protected static final int MAX_OBSTACLES = 5;
41+
protected static final float OBSTACLE_MOVEMENT_SPEED = 2.0f;
42+
protected static final int OBSTACLE_COLOR = Color.GREEN.main;
43+
protected final List<Rectangle> obstacles = new ObjectArrayList<>(MAX_OBSTACLES * 2);
44+
protected float obstacleWidth;
45+
46+
protected static final float GREG_SIZE = 18.0f;
47+
protected Rectangle gregArea = new Rectangle();
48+
protected float gregYSpeed = TERMINAL_VELOCITY;
49+
50+
@Nullable
51+
protected SingleActionSyncHandler syncHandler;
52+
protected boolean showStart = true;
53+
protected boolean setup = false;
54+
protected boolean init = false;
55+
protected boolean won = false;
56+
protected boolean collided = false;
57+
58+
protected IKey startMessage;
59+
protected IKey deathMessage;
60+
protected IKey respawnMessage;
61+
protected IKey wonMessage;
62+
63+
@Override
64+
public void onInit() {
65+
if (!GTValues.isClientSide()) return;
66+
67+
startMessage = IKey.lang("gregtech.machine.maintenance_hatch.fools.start")
68+
.style(TextFormatting.WHITE);
69+
70+
deathMessage = IKey.lang("gregtech.machine.maintenance_hatch.fools.dead")
71+
.style(TextFormatting.BOLD, TextFormatting.WHITE);
72+
73+
respawnMessage = IKey.lang("gregtech.machine.maintenance_hatch.fools.respawn")
74+
.style(TextFormatting.UNDERLINE, TextFormatting.WHITE);
75+
76+
wonMessage = IKey.lang("gregtech.machine.maintenance_hatch.fools.won")
77+
.style(TextFormatting.GREEN);
78+
}
79+
80+
@Override
81+
public void onResized() {
82+
super.onResized();
83+
if (!GTValues.isClientSide()) return;
84+
if (!setup) {
85+
setup = true;
86+
// Has to be in onResized instead of onInit since it depends on the size of the widget.
87+
initializeState();
88+
}
89+
}
90+
91+
@Override
92+
public boolean isValidSyncHandler(SyncHandler syncHandler) {
93+
return syncHandler instanceof SingleActionSyncHandler;
94+
}
95+
96+
/**
97+
* Set the action to take on the server when the client finishes the game.
98+
*/
99+
public FlappyGreg onFinish(@NotNull Runnable onFinish) {
100+
if (this.syncHandler == null) {
101+
this.syncHandler = new SingleActionSyncHandler();
102+
}
103+
104+
syncHandler.serverAction(onFinish);
105+
setSyncHandler(syncHandler);
106+
return this;
107+
}
108+
109+
@SideOnly(Side.CLIENT)
110+
protected void onFinish() {
111+
collided = false;
112+
if (syncHandler != null) {
113+
syncHandler.notifyServer();
114+
}
115+
}
116+
117+
protected boolean shouldUpdateGame() {
118+
return !init && !won && !collided && GTValues.isClientSide();
119+
}
120+
121+
protected void initializeState() {
122+
collided = false;
123+
obstacles.clear();
124+
125+
Area area = getArea();
126+
int width = area.width;
127+
int height = area.height;
128+
129+
gregArea = new Rectangle((width / 3.0f) - (GREG_SIZE / 2.0f), (height / 2.0f) - (GREG_SIZE / 2.0f), GREG_SIZE);
130+
131+
float lastXPos = width * 0.95f;
132+
this.obstacleWidth = width / 20.0f;
133+
for (int i = 0; i < MAX_OBSTACLES; i++) {
134+
Rectangle top = new Rectangle();
135+
obstacles.add(top);
136+
137+
Rectangle bottom = new Rectangle();
138+
obstacles.add(bottom);
139+
140+
top.setX(lastXPos);
141+
bottom.setX(lastXPos);
142+
top.setWidth(obstacleWidth);
143+
bottom.setWidth(obstacleWidth);
144+
145+
final float topYEnd = (height * 0.55f) - (height * 0.20f * GTValues.RNG.nextFloat());
146+
top.setHeight(topYEnd);
147+
148+
final float bottomYStart = topYEnd + (gregArea.getHeight() * 1.75f);
149+
bottom.setHeight(height - bottomYStart);
150+
bottom.setY(bottomYStart);
151+
152+
lastXPos += (width / 2.5f) + ((width / 15.0f) * GTValues.RNG.nextFloat());
153+
}
154+
155+
init = true;
156+
}
157+
158+
@Override
159+
public void onUpdate() {
160+
super.onUpdate();
161+
if (!shouldUpdateGame()) return;
162+
163+
updateGregPosition();
164+
checkObstacleCollisions();
165+
if (!collided) {
166+
updateObstaclePositions();
167+
checkWinState();
168+
}
169+
}
170+
171+
@SideOnly(Side.CLIENT)
172+
protected void updateGregPosition() {
173+
if (gregArea.getY() < (getArea().height - gregArea.getHeight())) {
174+
gregArea.setY(gregArea.getY() + gregYSpeed);
175+
}
176+
177+
if (gregYSpeed < TERMINAL_VELOCITY) {
178+
gregYSpeed = Math.min(gregYSpeed + GRAVITY, TERMINAL_VELOCITY);
179+
}
180+
}
181+
182+
@SideOnly(Side.CLIENT)
183+
protected void checkObstacleCollisions() {
184+
for (Rectangle obstacle : obstacles) {
185+
if (obstacle.collides(gregArea, OBSTACLE_MOVEMENT_SPEED)) {
186+
collided = true;
187+
break;
188+
}
189+
}
190+
}
191+
192+
@SideOnly(Side.CLIENT)
193+
protected void updateObstaclePositions() {
194+
for (Rectangle obstacle : obstacles) {
195+
obstacle.decrementX(OBSTACLE_MOVEMENT_SPEED);
196+
}
197+
}
198+
199+
@SideOnly(Side.CLIENT)
200+
protected void checkWinState() {
201+
if (obstacles.isEmpty()) return;
202+
203+
Rectangle obstacle = obstacles.get(obstacles.size() - 1);
204+
if ((obstacle.getX() + obstacleWidth + WIN_DISTANCE) <= gregArea.getX()) {
205+
won = true;
206+
collided = false;
207+
onFinish();
208+
}
209+
}
210+
211+
@Override
212+
public void draw(ModularGuiContext context, WidgetThemeEntry<?> widgetTheme) {
213+
Area area = getArea();
214+
int screenX = area.x;
215+
int screenY = area.y;
216+
int width = area.width;
217+
int height = area.height;
218+
219+
// Background
220+
GuiDraw.drawRect(0, 0, width, height, BACKGROUND_COLOR);
221+
222+
// Obstacles
223+
GL11.glEnable(GL11.GL_SCISSOR_TEST);
224+
RenderUtil.applyScissor(screenX, screenY, width, height);
225+
for (Rectangle obstacle : obstacles) {
226+
GuiDraw.drawRect(obstacle.getX(), obstacle.getY(), obstacle.getWidth(), obstacle.getHeight(),
227+
OBSTACLE_COLOR);
228+
}
229+
GL11.glDisable(GL11.GL_SCISSOR_TEST);
230+
231+
// "Character"
232+
GTGuiTextures.GREGTECH_LOGO.draw(gregArea.getX(), gregArea.getY(), gregArea.getWidth(), gregArea.getHeight());
233+
234+
if (showStart) {
235+
WidgetTheme theme = widgetTheme.getTheme();
236+
startMessage.draw(context, 0, (height / 2), width, 9, theme);
237+
}
238+
239+
if (collided) {
240+
GlStateManager.enableBlend();
241+
GuiDraw.drawRect(0, 0, width, height, 0x75FFFFFF & BACKGROUND_COLOR);
242+
GlStateManager.disableBlend();
243+
244+
WidgetTheme theme = widgetTheme.getTheme();
245+
deathMessage.draw(context, 0, (height / 2) - 5, width, 9, theme);
246+
respawnMessage.draw(context, 0, (height / 2) + 5, width, 9, theme);
247+
}
248+
249+
if (won) {
250+
WidgetTheme theme = widgetTheme.getTheme();
251+
wonMessage.draw(context, 0, (height / 2), width, 9, theme);
252+
}
253+
}
254+
255+
@Override
256+
public @NotNull Result onMousePressed(int mouseButton) {
257+
if (showStart) {
258+
showStart = false;
259+
}
260+
261+
if (init) {
262+
init = false;
263+
}
264+
265+
if (collided) {
266+
collided = false;
267+
initializeState();
268+
}
269+
270+
if (shouldUpdateGame()) {
271+
gregYSpeed = -CLICK_IMPULSE;
272+
return Result.SUCCESS;
273+
} else {
274+
return Result.IGNORE;
275+
}
276+
}
277+
}

0 commit comments

Comments
 (0)