添加载具数据同步包
This commit is contained in:
parent
760ef4d757
commit
d7d3431c70
6 changed files with 223 additions and 0 deletions
|
@ -0,0 +1,11 @@
|
|||
package com.atsuishio.superbwarfare.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 将指定字段标记为仅服务端启用,不会同步给客户端
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ElementType.FIELD})
|
||||
public @interface ServerOnly {
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.atsuishio.superbwarfare.data.vehicle;
|
||||
|
||||
import com.atsuishio.superbwarfare.annotation.ServerOnly;
|
||||
import com.atsuishio.superbwarfare.config.server.VehicleConfig;
|
||||
import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModify;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
@ -13,9 +14,11 @@ public class DefaultVehicleData {
|
|||
@SerializedName("MaxHealth")
|
||||
public float maxHealth = 50;
|
||||
|
||||
@ServerOnly
|
||||
@SerializedName("RepairCooldown")
|
||||
public int repairCooldown = VehicleConfig.REPAIR_COOLDOWN.get();
|
||||
|
||||
@ServerOnly
|
||||
@SerializedName("RepairAmount")
|
||||
public float repairAmount = VehicleConfig.REPAIR_AMOUNT.get().floatValue();
|
||||
|
||||
|
@ -31,9 +34,11 @@ public class DefaultVehicleData {
|
|||
@SerializedName("ApplyDefaultDamageModifiers")
|
||||
public boolean applyDefaultDamageModifiers = true;
|
||||
|
||||
@ServerOnly
|
||||
@SerializedName("DamageModifiers")
|
||||
public List<DamageModify> damageModifiers = List.of();
|
||||
|
||||
@ServerOnly
|
||||
@SerializedName("Mass")
|
||||
public float mass = 1;
|
||||
}
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
package com.atsuishio.superbwarfare.data.vehicle;
|
||||
|
||||
import com.atsuishio.superbwarfare.Mod;
|
||||
import com.atsuishio.superbwarfare.network.message.receive.GunsDataMessage;
|
||||
import com.atsuishio.superbwarfare.network.message.receive.VehiclesDataMessage;
|
||||
import com.google.gson.Gson;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.packs.resources.ResourceManager;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.event.OnDatapackSyncEvent;
|
||||
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
|
||||
import net.neoforged.neoforge.event.server.ServerStartedEvent;
|
||||
import net.neoforged.neoforge.network.PacketDistributor;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
|
@ -37,6 +42,13 @@ public class VehicleDataTool {
|
|||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) {
|
||||
if (event.getEntity() instanceof ServerPlayer player) {
|
||||
PacketDistributor.sendToPlayer(player, VehiclesDataMessage.create());
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void serverStarted(ServerStartedEvent event) {
|
||||
initJsonData(event.getServer().getResourceManager());
|
||||
|
@ -45,5 +57,7 @@ public class VehicleDataTool {
|
|||
@SubscribeEvent
|
||||
public static void onDataPackSync(OnDatapackSyncEvent event) {
|
||||
initJsonData(event.getPlayerList().getServer().getResourceManager());
|
||||
|
||||
event.getRelevantPlayers().forEach(player -> PacketDistributor.sendToPlayer(player, VehiclesDataMessage.create()));
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ public class NetworkRegistry {
|
|||
registrar.playToClient(SimulationDistanceMessage.TYPE, SimulationDistanceMessage.STREAM_CODEC, SimulationDistanceMessage::handler);
|
||||
registrar.playToClient(ClientTacticalSprintSyncMessage.TYPE, ClientTacticalSprintSyncMessage.STREAM_CODEC, (msg, ctx) -> ClientTacticalSprintSyncMessage.handler(msg));
|
||||
registrar.playToClient(DogTagEditorMessage.TYPE, DogTagEditorMessage.STREAM_CODEC, (msg, ctx) -> DogTagEditorMessage.handler(msg));
|
||||
registrar.playToClient(VehiclesDataMessage.TYPE, VehiclesDataMessage.STREAM_CODEC, (msg, ctx) -> VehiclesDataMessage.handler(msg));
|
||||
|
||||
registrar.playToServer(LaserShootMessage.TYPE, LaserShootMessage.STREAM_CODEC, LaserShootMessage::handler);
|
||||
registrar.playToServer(ShootMessage.TYPE, ShootMessage.STREAM_CODEC, ShootMessage::handler);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package com.atsuishio.superbwarfare.network.message.receive;
|
||||
|
||||
import com.atsuishio.superbwarfare.Mod;
|
||||
import com.atsuishio.superbwarfare.data.vehicle.DefaultVehicleData;
|
||||
import com.atsuishio.superbwarfare.data.vehicle.VehicleDataTool;
|
||||
import com.atsuishio.superbwarfare.tools.BufferSerializer;
|
||||
import com.google.gson.Gson;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public record VehiclesDataMessage(List<DefaultVehicleData> data) implements CustomPacketPayload {
|
||||
public static final Type<VehiclesDataMessage> TYPE = new Type<>(Mod.loc("set_vehicles_data"));
|
||||
|
||||
|
||||
public static final StreamCodec<FriendlyByteBuf, VehiclesDataMessage> STREAM_CODEC = StreamCodec.ofMember(
|
||||
(obj, buf) -> {
|
||||
buf.writeVarInt(obj.data.size());
|
||||
for (var data : obj.data) {
|
||||
buf.writeBytes(BufferSerializer.serialize(data).getSource());
|
||||
}
|
||||
},
|
||||
(buf) -> {
|
||||
var size = buf.readVarInt();
|
||||
var list = new ArrayList<DefaultVehicleData>();
|
||||
for (var i = 0; i < size; i++) {
|
||||
list.add(BufferSerializer.deserialize(buf, new DefaultVehicleData()));
|
||||
}
|
||||
return new VehiclesDataMessage(list);
|
||||
}
|
||||
);
|
||||
|
||||
public static VehiclesDataMessage create() {
|
||||
return new VehiclesDataMessage(VehicleDataTool.vehicleData.values().stream().toList());
|
||||
}
|
||||
|
||||
public static void handler(final VehiclesDataMessage message) {
|
||||
VehicleDataTool.vehicleData.clear();
|
||||
|
||||
for (var entry : message.data) {
|
||||
VehicleDataTool.vehicleData.put(entry.id, entry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
package com.atsuishio.superbwarfare.tools;
|
||||
|
||||
import com.atsuishio.superbwarfare.Mod;
|
||||
import com.atsuishio.superbwarfare.annotation.ServerOnly;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
// 屎
|
||||
// TODO 优化这一坨(至少得支持数组和嵌套对象序列化)
|
||||
public class BufferSerializer {
|
||||
public static List<Field> sortedFields(Class<?> clazz) {
|
||||
return Arrays.stream(clazz.getDeclaredFields())
|
||||
.filter(f -> !f.isAnnotationPresent(ServerOnly.class) && !f.getType().isAssignableFrom(Annotation.class))
|
||||
.sorted(Comparator.comparing(Field::getName))
|
||||
.toList();
|
||||
}
|
||||
|
||||
public static List<Field> sortedFields(Object object) {
|
||||
return sortedFields(object.getClass());
|
||||
}
|
||||
|
||||
public static List<Object> fieldValuesList(Object object) {
|
||||
var fields = new ArrayList<>();
|
||||
|
||||
for (var field : sortedFields(object)) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
Object value = field.get(object);
|
||||
fields.add(value);
|
||||
} catch (IllegalAccessException e) {
|
||||
Mod.LOGGER.error("BufferSerializer read error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
public static FriendlyByteBuf serialize(Object object) {
|
||||
var buffer = new FriendlyByteBuf(Unpooled.buffer());
|
||||
var fields = fieldValuesList(object);
|
||||
|
||||
fields.forEach(value -> {
|
||||
switch (value) {
|
||||
case Byte b -> buffer.writeByte(b);
|
||||
case Integer i -> buffer.writeVarInt(i);
|
||||
case Long l -> buffer.writeLong(l);
|
||||
case Float f -> buffer.writeFloat(f);
|
||||
case Double d -> buffer.writeDouble(d);
|
||||
case String s -> buffer.writeUtf(s);
|
||||
case Boolean b -> buffer.writeBoolean(b);
|
||||
// case List<?> l -> {
|
||||
// buffer.writeVarInt(l.size());
|
||||
// l.forEach(o -> serialize(o, buffer));
|
||||
// }
|
||||
|
||||
default -> serialize(value);
|
||||
}
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static <T> T deserialize(FriendlyByteBuf buffer, T object) {
|
||||
sortedFields(object).forEach(field -> {
|
||||
if (field.getType().isAssignableFrom(Byte.class) || field.getType().getName().equals("byte")) {
|
||||
setField(object, field, buffer.readByte());
|
||||
} else if (field.getType().isAssignableFrom(Integer.class) || field.getType().getName().equals("int")) {
|
||||
setField(object, field, buffer.readVarInt());
|
||||
} else if (field.getType().isAssignableFrom(Long.class) || field.getType().getName().equals("long")) {
|
||||
setField(object, field, buffer.readLong());
|
||||
} else if (field.getType().isAssignableFrom(Float.class) || field.getType().getName().equals("float")) {
|
||||
setField(object, field, buffer.readFloat());
|
||||
} else if (field.getType().isAssignableFrom(Double.class) || field.getType().getName().equals("double")) {
|
||||
setField(object, field, buffer.readDouble());
|
||||
} else if (field.getType().isAssignableFrom(String.class)) {
|
||||
setField(object, field, buffer.readUtf());
|
||||
} else if (field.getType().isAssignableFrom(Boolean.class) || field.getType().getName().equals("boolean")) {
|
||||
setField(object, field, buffer.readBoolean());
|
||||
// } else if (field.getType().isAssignableFrom(List.class)) {
|
||||
// var size = buffer.readVarInt();
|
||||
// var list = new ArrayList<>();
|
||||
// for (int i = 0; i < size; i++) {
|
||||
// list.add(readFieldByClass(object, field.getGenericType().getClass(), buffer));
|
||||
// }
|
||||
// setField(object, field, list);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Non-primary Object not supported");
|
||||
// setField(object, field, deserialize(buffer, getField(object, field)));
|
||||
}
|
||||
});
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
public static Object readFieldByClass(Object object, Class<?> clazz, FriendlyByteBuf buffer) {
|
||||
if (clazz.isAssignableFrom(Byte.class) || clazz.getName().equals("byte")) {
|
||||
return buffer.readByte();
|
||||
} else if (clazz.isAssignableFrom(Integer.class) || clazz.getName().equals("int")) {
|
||||
return buffer.readVarInt();
|
||||
} else if (clazz.isAssignableFrom(Long.class) || clazz.getName().equals("long")) {
|
||||
return buffer.readLong();
|
||||
} else if (clazz.isAssignableFrom(Float.class) || clazz.getName().equals("float")) {
|
||||
return buffer.readFloat();
|
||||
} else if (clazz.isAssignableFrom(Double.class) || clazz.getName().equals("double")) {
|
||||
return buffer.readDouble();
|
||||
} else if (clazz.isAssignableFrom(String.class)) {
|
||||
return buffer.readUtf();
|
||||
} else if (clazz.isAssignableFrom(Boolean.class) || clazz.getName().equals("boolean")) {
|
||||
return buffer.readByte();
|
||||
// } else if (clazz.isAssignableFrom(List.class)) {
|
||||
// var size = buffer.readVarInt();
|
||||
// var list = new ArrayList<>();
|
||||
// for (int i = 0; i < size; i++) {
|
||||
// clazz.getDeclaredConstructors()[0].newInstance()
|
||||
// list.add(deserialize(field));
|
||||
// }
|
||||
// setField(object, field, list);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Non-primary Object not supported");
|
||||
// deserialize(buffer, getField(object, field));
|
||||
}
|
||||
}
|
||||
|
||||
public static void setField(Object object, Field field, Object value) {
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
field.set(object, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
Mod.LOGGER.error("BufferSerializer write error: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue