Skip to content

Commit 3346c0d

Browse files
committed
feat: more lua slop generation, draft of sidebar
1 parent 8e30b9b commit 3346c0d

File tree

15 files changed

+438
-179
lines changed

15 files changed

+438
-179
lines changed

modules/common/src/main/java/net/hollowcube/common/util/StringUtil.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,17 @@ public final class StringUtil {
1616
}
1717
return pascalCase.toString();
1818
}
19+
20+
public static @NotNull String pascalToSnake(@NotNull String pascalCase) {
21+
StringBuilder snakeCase = new StringBuilder();
22+
for (int i = 0; i < pascalCase.length(); i++) {
23+
char c = pascalCase.charAt(i);
24+
if (Character.isUpperCase(c) && i > 0) {
25+
snakeCase.append('_');
26+
}
27+
snakeCase.append(Character.toLowerCase(c));
28+
}
29+
return snakeCase.toString();
30+
}
31+
1932
}

modules/map-runtime/src/main/java/net/hollowcube/mapmaker/runtime/freeform/FreeformMapWorld.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010
import net.hollowcube.mapmaker.runtime.freeform.lua.LuaEventSource;
1111
import net.hollowcube.mapmaker.runtime.freeform.lua.LuaGlobals;
1212
import net.hollowcube.mapmaker.runtime.freeform.lua.LuaTask;
13+
import net.hollowcube.mapmaker.runtime.freeform.lua.base.LuaTextImpl$luau;
1314
import net.hollowcube.mapmaker.runtime.freeform.lua.math.LuaVectorTypeImpl;
14-
import net.hollowcube.mapmaker.runtime.freeform.lua.player.LuaPlayer;
15-
import net.hollowcube.mapmaker.runtime.freeform.lua.world.LuaBlock;
15+
import net.hollowcube.mapmaker.runtime.freeform.lua.player.LuaPlayer$luau;
16+
import net.hollowcube.mapmaker.runtime.freeform.lua.player.LuaSidebar$luau;
17+
import net.hollowcube.mapmaker.runtime.freeform.lua.world.LuaBlockImpl$luau;
1618
import net.hollowcube.mapmaker.runtime.freeform.lua.world.LuaWorld;
19+
import net.hollowcube.mapmaker.runtime.freeform.lua.world.LuaWorld$luau;
1720
import net.hollowcube.mapmaker.runtime.freeform.script.LuaScriptState;
1821
import net.kyori.adventure.bossbar.BossBar;
1922
import net.minestom.server.entity.Player;
@@ -145,14 +148,21 @@ private static LuaState createGlobalState() {
145148
// Global APIs
146149
LuaVectorTypeImpl.init(global);
147150
// LuaColor.init(global);
148-
// LuaText.init(global);
151+
LuaTextImpl$luau.init$luau(global);
149152

150153
LuaEventSource.init(global);
151-
LuaBlock.init(global);
152-
LuaWorld.init(global);
154+
LuaBlockImpl$luau.init$luau(global);
155+
LuaWorld$luau.init$luau(global);
153156
// LuaParticle.init(global);
154157
// LuaEntity.init(global);
155-
LuaPlayer.init(global);
158+
159+
// Player & friends
160+
LuaPlayer$luau.init$luau(global);
161+
LuaSidebar$luau.init$luau(global);
162+
163+
// TODO for gen
164+
// - use tagged user data (and a more generic way to add to state)
165+
// - use service files to discover impls and load them.
156166

157167
global.sandbox();
158168
return global;

modules/map-runtime/src/main/java/net/hollowcube/mapmaker/runtime/freeform/lua/LuaTask.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.Map;
1111
import java.util.function.Supplier;
1212

13+
// @LuaLib("task")
1314
public class LuaTask {
1415
private static final String NAME = "task";
1516

modules/map-runtime/src/main/java/net/hollowcube/mapmaker/runtime/freeform/lua/api-sketching.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,11 @@ task.cancel(handle)
9797
* `#` to get length
9898
* `==` to compare
9999
* `~=` to compare
100+
* `tostring` to serialize to plain text
100101
* Instance methods
101-
* some way to serialize to plain text
102102
* `Direction` - `Direction.North`, `.South`, etc
103103
* `Slot` - Special slot constants, eg `Slot.MainHand`, `.Saddle`, etc
104+
* Could probably be tagged light userdata constants
104105

105106
## Content Types
106107

@@ -239,6 +240,8 @@ Movement
239240
Communication
240241

241242
* `SendMessage(message: AnyText)`
243+
* `SendChatPrompt(message: AnyText, options: { [key: string]: AnyText }): string` -> sends the message and gives
244+
clickable response options in the response.
242245
* `ShowTitle(title: AnyText, subtitle?: AnyText, { fadeIn?: number, stay?: number, fadeOut?: number }?)`
243246
* `ShowActionBar(message: AnyText, duration?: number)`
244247
* `Sidebar` - Sidebar object controls the sidebar

modules/map-runtime/src/main/java/net/hollowcube/mapmaker/runtime/freeform/lua/base/LuaText.java renamed to modules/map-runtime/src/main/java/net/hollowcube/mapmaker/runtime/freeform/lua/base/LuaTextImpl.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
//todo dont really need to inherit from the generated type. we just get TYPE_NAME from it.
1515
// type name should also go away because we should be using tagged userdata.
1616
@LuaType(implFor = Component.class, name = "Text")
17-
public class LuaText implements LuaText$luau {
17+
public class LuaTextImpl implements LuaTextImpl$luau {
1818
private static final PlainTextComponentSerializer PLAIN_TEXT_SERIALIZER =
1919
PlainTextComponentSerializer.plainText();
2020
// Extremely limited mini message for now, likely will expand in the future.
@@ -41,6 +41,23 @@ public static Component checkArg(LuaState state, int index) {
4141
return (Component) state.checkUserDataArg(index, TYPE_NAME);
4242
}
4343

44+
public static Component checkAnyTextArg(LuaState state, int index) {
45+
state.checkAny(index); // Make sure they provided an arg
46+
return switch (state.type(index)) {
47+
case STRING -> Component.text(state.toString(index));
48+
case NUMBER, BOOLEAN, VECTOR -> Component.text(state.toStringRepr(index));
49+
case TABLE -> {
50+
state.argError(index, "Table to text is not yet supported");
51+
yield null;
52+
}
53+
case USERDATA -> checkArg(state, index);
54+
default -> {
55+
state.argError(index, "Expected a Text-able object");
56+
yield null;
57+
}
58+
};
59+
}
60+
4461
//region Static Methods
4562

4663
/// Construct a new Text object from a minimessage string.
@@ -81,6 +98,21 @@ public static int sanitize(LuaState state) {
8198

8299
//region Meta Methods
83100

101+
@LuaMeta(MetaType.CONCAT)
102+
public static int luaConcat(LuaState state) {
103+
var lhs = checkArg(state, 1);
104+
var rhs = checkAnyTextArg(state, 2);
105+
push(state, Component.textOfChildren(lhs, rhs));
106+
return 1;
107+
}
108+
109+
@LuaMeta(MetaType.LEN)
110+
public static int luaLen(LuaState state) {
111+
var component = checkArg(state, 1);
112+
state.pushInteger(PLAIN_TEXT_SERIALIZER.serialize(component).length());
113+
return 1;
114+
}
115+
84116
@LuaMeta(MetaType.TOSTRING)
85117
public static int luaToString(LuaState state) {
86118
var component = checkArg(state, 1);

modules/map-runtime/src/main/java/net/hollowcube/mapmaker/runtime/freeform/lua/player/LuaPlayer.java

Lines changed: 48 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,43 +2,35 @@
22

33
import com.google.gson.JsonObject;
44
import net.hollowcube.luau.LuaState;
5+
import net.hollowcube.luau.annotation.LuaProperty;
6+
import net.hollowcube.luau.annotation.LuaType;
57
import net.hollowcube.mapmaker.runtime.freeform.lua.LuaEventSource;
8+
import net.hollowcube.mapmaker.runtime.freeform.lua.base.LuaTextImpl;
69
import net.hollowcube.mapmaker.runtime.freeform.lua.math.LuaVectorTypeImpl;
7-
import net.hollowcube.mapmaker.runtime.freeform.lua.world.LuaBlock;
10+
import net.hollowcube.mapmaker.runtime.freeform.lua.world.LuaBlockImpl;
811
import net.hollowcube.mapmaker.runtime.freeform.script.LuaHelpers;
912
import net.minestom.server.entity.Player;
1013
import net.minestom.server.event.player.PlayerBlockInteractEvent;
14+
import org.jetbrains.annotations.Nullable;
1115

12-
import static net.hollowcube.mapmaker.runtime.freeform.script.LuaHelpers.noSuchKey;
13-
import static net.hollowcube.mapmaker.runtime.freeform.script.LuaHelpers.noSuchMethod;
14-
15-
public class LuaPlayer {
16-
private static final String NAME = "Player";
17-
18-
public static void init(LuaState state) {
19-
state.newMetaTable(NAME);
20-
state.pushCFunction(LuaPlayer::luaIndex, "__index");
21-
state.setField(-2, "__index");
22-
state.pushCFunction(LuaPlayer::luaNewIndex, "__newindex");
23-
state.setField(-2, "__newindex");
24-
state.pushCFunction(LuaPlayer::luaNameCall, "__namecall");
25-
state.setField(-2, "__namecall");
26-
state.pop(1);
27-
}
16+
@LuaType
17+
public class LuaPlayer implements LuaPlayer$luau {
2818

2919
public static void push(LuaState state, LuaPlayer entity) {
3020
state.newUserData(entity);
31-
state.getMetaTable(NAME);
21+
state.getMetaTable(TYPE_NAME);
3222
state.setMetaTable(-2);
3323
}
3424

3525
public static LuaPlayer checkArg(LuaState state, int index) {
36-
return (LuaPlayer) state.checkUserDataArg(index, NAME);
26+
return (LuaPlayer) state.checkUserDataArg(index, TYPE_NAME);
3727
}
3828

3929
private final Player player;
4030
private final int saveDataRef;
4131

32+
private @Nullable LuaSidebar sidebar; // Lazy
33+
4234
public LuaPlayer(LuaState state, Player player, JsonObject saveData) {
4335
this.player = player;
4436

@@ -47,62 +39,61 @@ public LuaPlayer(LuaState state, Player player, JsonObject saveData) {
4739
state.pop(1);
4840
}
4941

50-
// Properties
51-
52-
private int getUuid(LuaState state) {
42+
@LuaProperty
43+
public int getUuid(LuaState state) {
5344
state.pushString(player.getUuid().toString());
5445
return 1;
5546
}
5647

57-
private int getSaveData(LuaState state) {
48+
@LuaProperty
49+
public int getName(LuaState state) {
50+
state.pushString(player.getUsername());
51+
return 1;
52+
}
53+
54+
//region Communication
55+
56+
@LuaProperty
57+
public int getSidebar(LuaState state) {
58+
if (sidebar == null) sidebar = new LuaSidebar(player);
59+
LuaSidebar.push(state, sidebar);
60+
return 1;
61+
}
62+
63+
public int sendMessage(LuaState state) {
64+
var message = LuaTextImpl.checkAnyTextArg(state, 1);
65+
player.sendMessage(message);
66+
return 0;
67+
}
68+
69+
//endregion
70+
71+
//region Persistence
72+
73+
@LuaProperty
74+
public int getSaveData(LuaState state) {
5875
state.getref(saveDataRef);
5976
return 1;
6077
}
6178

62-
private int getOnBlockInteract(LuaState state) {
79+
//endregion Persistence
80+
81+
//region Events
82+
83+
@LuaProperty
84+
public int getOnBlockInteract(LuaState state) {
6385
LuaEventSource.push(state, new LuaEventSource<>(
6486
player.eventNode(),
6587
PlayerBlockInteractEvent.class,
6688
(eventState, event) -> {
6789
LuaVectorTypeImpl.push(eventState, event.getBlockPosition());
68-
LuaBlock.push(eventState, event.getBlock());
90+
LuaBlockImpl.push(eventState, event.getBlock());
6991
return 2;
7092
}
7193
));
7294
return 1;
7395
}
7496

75-
// Methods
97+
//endregion
7698

77-
// Metamethods
78-
79-
private static int luaIndex(LuaState state) {
80-
final LuaPlayer self = checkArg(state, 1);
81-
final String key = state.checkStringArg(2);
82-
return switch (key) {
83-
case "Uuid" -> self.getUuid(state);
84-
case "SaveData" -> self.getSaveData(state);
85-
case "OnBlockInteract" -> self.getOnBlockInteract(state);
86-
default -> noSuchKey(state, NAME, key);
87-
};
88-
}
89-
90-
private static int luaNewIndex(LuaState state) {
91-
final LuaPlayer self = checkArg(state, 1);
92-
final String key = state.checkStringArg(2);
93-
state.remove(1); // Remove the userdata from the stack
94-
state.remove(1); // Remove the key from the stack
95-
return switch (key) {
96-
default -> noSuchKey(state, NAME, key);
97-
};
98-
}
99-
100-
private static int luaNameCall(LuaState state) {
101-
final LuaPlayer self = checkArg(state, 1);
102-
state.remove(1); // Remove the world userdata from the stack (so implementations can pretend they have no self)
103-
final String methodName = state.nameCallAtom();
104-
return switch (methodName) {
105-
default -> noSuchMethod(state, NAME, methodName);
106-
};
107-
}
10899
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package net.hollowcube.mapmaker.runtime.freeform.lua.player;
2+
3+
import net.hollowcube.luau.LuaState;
4+
import net.hollowcube.luau.annotation.LuaProperty;
5+
import net.hollowcube.luau.annotation.LuaType;
6+
import net.hollowcube.mapmaker.runtime.freeform.lua.base.LuaTextImpl;
7+
import net.kyori.adventure.text.Component;
8+
import net.minestom.server.entity.Player;
9+
import net.minestom.server.scoreboard.Sidebar;
10+
11+
@LuaType
12+
public class LuaSidebar implements LuaSidebar$luau {
13+
14+
public static void push(LuaState state, LuaSidebar value) {
15+
state.newUserData(value);
16+
state.getMetaTable(TYPE_NAME);
17+
state.setMetaTable(-2);
18+
}
19+
20+
public static LuaSidebar checkArg(LuaState state, int index) {
21+
return (LuaSidebar) state.checkUserDataArg(index, TYPE_NAME);
22+
}
23+
24+
private final Sidebar sidebar;
25+
private final Player player;
26+
27+
// Not stored on Sidebar and we want to be able to return it, so stored here.
28+
private Component title = Component.empty();
29+
30+
public LuaSidebar(Player player) {
31+
this.sidebar = new Sidebar(title);
32+
this.player = player;
33+
}
34+
35+
@LuaProperty
36+
public int getEnabled(LuaState state) {
37+
state.pushBoolean(sidebar.isViewer(player));
38+
return 1;
39+
}
40+
41+
@LuaProperty
42+
public int setEnabled(LuaState state) {
43+
boolean newValue = state.checkBooleanArg(1);
44+
if (newValue) sidebar.addViewer(player);
45+
else sidebar.removeViewer(player);
46+
return 1;
47+
}
48+
49+
@LuaProperty
50+
public int getTitle(LuaState state) {
51+
LuaTextImpl.push(state, title);
52+
return 1;
53+
}
54+
55+
@LuaProperty
56+
public int setTitle(LuaState state) {
57+
title = LuaTextImpl.checkAnyTextArg(state, 1);
58+
sidebar.setTitle(title);
59+
return 1;
60+
}
61+
62+
}

0 commit comments

Comments
 (0)