mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-13 22:43:51 +01:00
Added getSchedule to train station lua API
- Added getSchedule which serializes the currently present train's schedule into a lua table - Refactored StationPeripheral#setSchedule to use a more generic method of serializing NBT tags to lua tables - Moved schedule entry special data from root tag to "Data" - Added StringHelper#camelCaseToSnakeCase - Added variety of put methods to CreateLuaTable
This commit is contained in:
parent
31ad3aa671
commit
909484ed5b
9 changed files with 242 additions and 96 deletions
|
@ -3,20 +3,30 @@ package com.simibubi.create.compat.computercraft;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaValues;
|
||||
import dan200.computercraft.api.lua.ObjectLuaTable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CreateLuaTable extends ObjectLuaTable {
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaTable;
|
||||
import dan200.computercraft.api.lua.LuaValues;
|
||||
|
||||
public class CreateLuaTable implements LuaTable<Object, Object> {
|
||||
|
||||
private final Map<Object, Object> map;
|
||||
|
||||
public CreateLuaTable() {
|
||||
this.map = new HashMap<>();
|
||||
}
|
||||
|
||||
public CreateLuaTable(Map<?, ?> map) {
|
||||
super(map);
|
||||
this.map = new HashMap<>(map);
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key) throws LuaException {
|
||||
|
@ -86,4 +96,77 @@ public class CreateLuaTable extends ObjectLuaTable {
|
|||
return Collections.unmodifiableList(tables);
|
||||
}
|
||||
|
||||
public Map<Object, Object> getMap() {
|
||||
return map;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object put(Object key, Object value) {
|
||||
return map.put(key, value);
|
||||
}
|
||||
|
||||
public void putBoolean(String key, boolean value) {
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
public void putDouble(String key, double value) {
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
public void putString(String key, String value) {
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
public void putTable(String key, CreateLuaTable value) {
|
||||
map.put(key, value);
|
||||
}
|
||||
|
||||
public void putTable(int i, CreateLuaTable value) {
|
||||
map.put(i, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return map.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return map.containsKey(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return map.containsValue(o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object get(Object o) {
|
||||
return map.get(o);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Object> keySet() {
|
||||
return map.keySet();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<Object> values() {
|
||||
return map.values();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Set<Entry<Object, Object>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package com.simibubi.create.compat.computercraft.peripherals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.simibubi.create.compat.computercraft.CreateLuaTable;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||
|
@ -10,20 +12,21 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.station
|
|||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.TrainEditPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.Schedule;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleEntry;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduleWaitCondition;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.destination.ScheduleInstruction;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.Components;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.StringHelper;
|
||||
|
||||
import dan200.computercraft.api.lua.IArguments;
|
||||
import dan200.computercraft.api.lua.LuaException;
|
||||
import dan200.computercraft.api.lua.LuaFunction;
|
||||
import net.minecraft.nbt.ByteTag;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import net.minecraft.nbt.DoubleTag;
|
||||
import net.minecraft.nbt.IntTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NumericTag;
|
||||
import net.minecraft.nbt.StringTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraftforge.network.PacketDistributor;
|
||||
|
||||
public class StationPeripheral extends SyncedPeripheral<StationTileEntity> {
|
||||
|
@ -127,6 +130,23 @@ public class StationPeripheral extends SyncedPeripheral<StationTileEntity> {
|
|||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainEditPacket.TrainEditReturnPacket(train.id, name, train.icon.getId()));
|
||||
}
|
||||
|
||||
@LuaFunction
|
||||
public final CreateLuaTable getSchedule() throws LuaException {
|
||||
GlobalStation station = tile.getStation();
|
||||
if (station == null)
|
||||
throw new LuaException("train station does not exist");
|
||||
|
||||
Train train = station.getPresentTrain();
|
||||
if (train == null)
|
||||
throw new LuaException("there is no train present");
|
||||
|
||||
Schedule schedule = train.runtime.getSchedule();
|
||||
if (schedule == null)
|
||||
throw new LuaException("train doesn't have a schedule");
|
||||
|
||||
return fromCompoundTag(schedule.write());
|
||||
}
|
||||
|
||||
@LuaFunction(mainThread = true)
|
||||
public final void setSchedule(IArguments arguments) throws LuaException {
|
||||
GlobalStation station = tile.getStation();
|
||||
|
@ -137,87 +157,100 @@ public class StationPeripheral extends SyncedPeripheral<StationTileEntity> {
|
|||
if (train == null)
|
||||
throw new LuaException("there is no train present");
|
||||
|
||||
Schedule schedule = parseSchedule(arguments);
|
||||
train.runtime.setSchedule(schedule, true);
|
||||
Schedule schedule = Schedule.fromTag(toCompoundTag(new CreateLuaTable(arguments.getTable(0))));
|
||||
boolean autoSchedule = train.runtime.getSchedule() == null || train.runtime.isAutoSchedule;
|
||||
train.runtime.setSchedule(schedule, autoSchedule);
|
||||
}
|
||||
|
||||
private static Schedule parseSchedule(IArguments arguments) throws LuaException {
|
||||
CreateLuaTable scheduleTable = new CreateLuaTable(arguments.getTable(0));
|
||||
Schedule schedule = new Schedule();
|
||||
private static @NotNull CreateLuaTable fromCompoundTag(CompoundTag tag) throws LuaException {
|
||||
return (CreateLuaTable) fromNBTTag(null, tag);
|
||||
}
|
||||
|
||||
schedule.cyclic = scheduleTable.getOptBoolean("cyclic").orElse(true);
|
||||
CreateLuaTable entriesTable = scheduleTable.getTable("entries");
|
||||
private static @NotNull Object fromNBTTag(@Nullable String key, Tag tag) throws LuaException {
|
||||
byte type = tag.getId();
|
||||
|
||||
for (CreateLuaTable entryTable : entriesTable.tableValues()) {
|
||||
ScheduleEntry entry = new ScheduleEntry();
|
||||
if (type == Tag.TAG_BYTE && key != null && key.equals("Count"))
|
||||
return ((NumericTag) tag).getAsByte();
|
||||
else if (type == Tag.TAG_BYTE)
|
||||
return ((NumericTag) tag).getAsByte() != 0;
|
||||
else if (type == Tag.TAG_INT || type == Tag.TAG_LONG)
|
||||
return ((NumericTag) tag).getAsLong();
|
||||
else if (type == Tag.TAG_FLOAT || type == Tag.TAG_DOUBLE)
|
||||
return ((NumericTag) tag).getAsDouble();
|
||||
else if (type == Tag.TAG_STRING)
|
||||
return tag.getAsString();
|
||||
else if (type == Tag.TAG_LIST) {
|
||||
CreateLuaTable list = new CreateLuaTable();
|
||||
ListTag listTag = (ListTag) tag;
|
||||
|
||||
entry.instruction = getInstruction(entryTable);
|
||||
|
||||
// Add conditions
|
||||
if (entry.instruction.supportsConditions()) {
|
||||
for (CreateLuaTable conditionsListTable : entryTable.getTable("conditions").tableValues()) {
|
||||
List<ScheduleWaitCondition> conditionsList = new ArrayList<>();
|
||||
|
||||
for (CreateLuaTable conditionTable : conditionsListTable.tableValues()) {
|
||||
conditionsList.add(getCondition(conditionTable));
|
||||
}
|
||||
|
||||
entry.conditions.add(conditionsList);
|
||||
}
|
||||
for (int i = 0; i < listTag.size(); i++) {
|
||||
list.put(i + 1, fromNBTTag(null, listTag.get(i)));
|
||||
}
|
||||
|
||||
schedule.entries.add(entry);
|
||||
return list;
|
||||
|
||||
} else if (type == Tag.TAG_COMPOUND) {
|
||||
CreateLuaTable table = new CreateLuaTable();
|
||||
CompoundTag compoundTag = (CompoundTag) tag;
|
||||
|
||||
for (String compoundKey : compoundTag.getAllKeys()) {
|
||||
table.put(
|
||||
StringHelper.camelCaseToSnakeCase(compoundKey),
|
||||
fromNBTTag(compoundKey, compoundTag.get(compoundKey))
|
||||
);
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
return schedule;
|
||||
throw new LuaException("unknown tag type " + tag.getType().getName());
|
||||
}
|
||||
|
||||
private static ScheduleInstruction getInstruction(CreateLuaTable entry) throws LuaException {
|
||||
ResourceLocation location = new ResourceLocation(entry.getString("instruction"));
|
||||
|
||||
for (Pair<ResourceLocation, Supplier<? extends ScheduleInstruction>> pair : Schedule.INSTRUCTION_TYPES)
|
||||
if (pair.getFirst().equals(location)) {
|
||||
ScheduleInstruction instruction = pair.getSecond().get();
|
||||
instruction.setData(getEntryData(entry.getTable("data")));
|
||||
|
||||
return instruction;
|
||||
}
|
||||
|
||||
throw new LuaException("instruction " + location + " is not a valid instruction type");
|
||||
private static @NotNull CompoundTag toCompoundTag(CreateLuaTable table) throws LuaException {
|
||||
return (CompoundTag) toNBTTag(null, table.getMap());
|
||||
}
|
||||
|
||||
private static ScheduleWaitCondition getCondition(CreateLuaTable entry) throws LuaException {
|
||||
ResourceLocation location = new ResourceLocation(entry.getString("condition"));
|
||||
|
||||
for (Pair<ResourceLocation, Supplier<? extends ScheduleWaitCondition>> pair : Schedule.CONDITION_TYPES)
|
||||
if (pair.getFirst().equals(location)) {
|
||||
ScheduleWaitCondition condition = pair.getSecond().get();
|
||||
condition.setData(getEntryData(entry.getTable("data")));
|
||||
|
||||
return condition;
|
||||
}
|
||||
|
||||
throw new LuaException("condition " + location + " is not a valid condition type");
|
||||
}
|
||||
|
||||
private static CompoundTag getEntryData(CreateLuaTable data) throws LuaException {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
|
||||
for (String key : data.stringKeySet()) {
|
||||
String tagKey = StringHelper.snakeCaseToCamelCase(key);
|
||||
Object value = data.get(key);
|
||||
|
||||
if (value instanceof Boolean)
|
||||
tag.putBoolean(tagKey, (Boolean) value);
|
||||
else if (value instanceof Number)
|
||||
tag.putDouble(tagKey, ((Number) value).doubleValue());
|
||||
else if (value instanceof String)
|
||||
tag.putString(tagKey, (String) value);
|
||||
private static @NotNull Tag toNBTTag(@Nullable String key, Object value) throws LuaException {
|
||||
if (value instanceof Boolean v)
|
||||
return ByteTag.valueOf(v);
|
||||
else if (value instanceof Byte || (key != null && key.equals("count")))
|
||||
return ByteTag.valueOf(((Number) value).byteValue());
|
||||
else if (value instanceof Number v) {
|
||||
// If number is numerical integer
|
||||
if (v.intValue() == v.doubleValue())
|
||||
return IntTag.valueOf(v.intValue());
|
||||
else
|
||||
throw new LuaException("");
|
||||
return DoubleTag.valueOf(v.doubleValue());
|
||||
|
||||
} else if (value instanceof String v)
|
||||
return StringTag.valueOf(v);
|
||||
else if (value instanceof Map<?, ?> v && v.containsKey(1.0)) { // List
|
||||
ListTag list = new ListTag();
|
||||
for (Object o : v.values()) {
|
||||
list.add(toNBTTag(null, o));
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
} else if (value instanceof Map<?, ?> v) { // Table/Map
|
||||
CompoundTag compound = new CompoundTag();
|
||||
for (Object objectKey : v.keySet()) {
|
||||
if (!(objectKey instanceof String compoundKey))
|
||||
throw new LuaException("table key is not of type string");
|
||||
|
||||
compound.put(
|
||||
// Items serialize their resource location as "id" and not as "Id".
|
||||
// This check is needed to see if the 'i' should be left lowercase or not.
|
||||
// Items store "count" in the same compound tag, so we can check for its presence to see if this is a serialized item
|
||||
compoundKey.equals("id") && v.containsKey("count") ? "id" : StringHelper.snakeCaseToCamelCase(compoundKey),
|
||||
toNBTTag(compoundKey, v.get(compoundKey))
|
||||
);
|
||||
}
|
||||
|
||||
return compound;
|
||||
}
|
||||
|
||||
return tag;
|
||||
throw new LuaException("unknown object type " + value.getClass().getName());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
|
|
@ -18,6 +18,7 @@ public abstract class ScheduleDataEntry implements IScheduleInput {
|
|||
@Override
|
||||
public void setData(CompoundTag data) {
|
||||
this.data = data;
|
||||
readAdditional(data);
|
||||
}
|
||||
|
||||
protected void writeAdditional(CompoundTag tag) {};
|
||||
|
|
|
@ -68,7 +68,8 @@ public class FluidThresholdCondition extends CargoThresholdCondition {
|
|||
@Override
|
||||
protected void readAdditional(CompoundTag tag) {
|
||||
super.readAdditional(tag);
|
||||
compareStack = ItemStack.of(tag.getCompound("Bucket"));
|
||||
if (tag.contains("Bucket"))
|
||||
compareStack = ItemStack.of(tag.getCompound("Bucket"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,4 +140,4 @@ public class FluidThresholdCondition extends CargoThresholdCondition {
|
|||
Math.max(0, getThreshold() + offset), Lang.translateDirect("schedule.condition.threshold.buckets"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,8 @@ public class ItemThresholdCondition extends CargoThresholdCondition {
|
|||
@Override
|
||||
protected void readAdditional(CompoundTag tag) {
|
||||
super.readAdditional(tag);
|
||||
stack = ItemStack.of(tag.getCompound("Item"));
|
||||
if (tag.contains("Item"))
|
||||
stack = ItemStack.of(tag.getCompound("Item"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -131,4 +132,4 @@ public class ItemThresholdCondition extends CargoThresholdCondition {
|
|||
Math.max(0, getThreshold() + offset),
|
||||
Lang.translateDirect("schedule.condition.threshold." + (inStacks() ? "stacks" : "items")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,7 +107,8 @@ public class RedstoneLinkCondition extends ScheduleWaitCondition {
|
|||
|
||||
@Override
|
||||
protected void readAdditional(CompoundTag tag) {
|
||||
freq = Couple.deserializeEach(tag.getList("Frequency", Tag.TAG_COMPOUND), c -> Frequency.of(ItemStack.of(c)));
|
||||
if (tag.contains("Frequency"))
|
||||
freq = Couple.deserializeEach(tag.getList("Frequency", Tag.TAG_COMPOUND), c -> Frequency.of(ItemStack.of(c)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -118,7 +119,7 @@ public class RedstoneLinkCondition extends ScheduleWaitCondition {
|
|||
.titled(Lang.translateDirect("schedule.condition.redstone_link.frequency_state")),
|
||||
"Inverted");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MutableComponent getWaitingStatus(Level level, Train train, CompoundTag tag) {
|
||||
return Lang.translateDirect("schedule.condition.redstone_link.status");
|
||||
|
|
|
@ -16,16 +16,17 @@ import net.minecraft.world.level.Level;
|
|||
public abstract class ScheduleWaitCondition extends ScheduleDataEntry {
|
||||
|
||||
public abstract boolean tickCompletion(Level level, Train train, CompoundTag context);
|
||||
|
||||
|
||||
protected void requestStatusToUpdate(CompoundTag context) {
|
||||
context.putInt("StatusVersion", context.getInt("StatusVersion") + 1);
|
||||
}
|
||||
|
||||
|
||||
public final CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
CompoundTag dataCopy = data.copy();
|
||||
writeAdditional(dataCopy);
|
||||
tag.putString("Id", getId().toString());
|
||||
tag.put("Data", data.copy());
|
||||
writeAdditional(tag);
|
||||
tag.put("Data", dataCopy);
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
@ -43,11 +44,14 @@ public abstract class ScheduleWaitCondition extends ScheduleDataEntry {
|
|||
}
|
||||
|
||||
ScheduleWaitCondition condition = supplier.get();
|
||||
condition.data = tag.getCompound("Data");
|
||||
// Left around for migration purposes. Data added in writeAdditional has moved into the "Data" tag
|
||||
condition.readAdditional(tag);
|
||||
CompoundTag data = tag.getCompound("Data");
|
||||
condition.readAdditional(data);
|
||||
condition.data = data;
|
||||
return condition;
|
||||
}
|
||||
|
||||
public abstract MutableComponent getWaitingStatus(Level level, Train train, CompoundTag tag);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,9 +16,10 @@ public abstract class ScheduleInstruction extends ScheduleDataEntry {
|
|||
|
||||
public final CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
CompoundTag dataCopy = data.copy();
|
||||
writeAdditional(dataCopy);
|
||||
tag.putString("Id", getId().toString());
|
||||
tag.put("Data", data.copy());
|
||||
writeAdditional(tag);
|
||||
tag.put("Data", dataCopy);
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
@ -36,9 +37,12 @@ public abstract class ScheduleInstruction extends ScheduleDataEntry {
|
|||
}
|
||||
|
||||
ScheduleInstruction scheduleDestination = supplier.get();
|
||||
scheduleDestination.data = tag.getCompound("Data");
|
||||
// Left around for migration purposes. Data added in writeAdditional has moved into the "Data" tag
|
||||
scheduleDestination.readAdditional(tag);
|
||||
CompoundTag data = tag.getCompound("Data");
|
||||
scheduleDestination.readAdditional(data);
|
||||
scheduleDestination.data = data;
|
||||
return scheduleDestination;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,4 +25,22 @@ public class StringHelper {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
public static String camelCaseToSnakeCase(String text) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (char c : text.toCharArray()) {
|
||||
if (Character.isUpperCase(c)) {
|
||||
builder.append('_');
|
||||
builder.append(Character.toLowerCase(c));
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (builder.length() > 0 && builder.charAt(0) == '_')
|
||||
builder.deleteCharAt(0);
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue