Compare commits

...

10 commits

Author SHA1 Message Date
Light_Quanta
ba147903dd
移除无人机上的额外C4模型 2025-07-01 12:20:05 +08:00
Light_Quanta
4014507e41
缓存无人机渲染的挂载实体 2025-07-01 12:09:22 +08:00
Light_Quanta
21dc782fb7
进一步完善自定义挂载,将RPG和C4挂载修改为数据包自定义 2025-07-01 11:38:36 +08:00
Light_Quanta
7b0f0959a2
尝试使用数据包控制无人机挂载 2025-07-01 04:50:05 +08:00
Light_Quanta
cbc71d062a
重写数据包加载 2025-07-01 03:37:45 +08:00
17146
afdb50c1d7
可能是真修复is导致的空判断异常 2025-06-30 23:44:01 +08:00
17146
1831f900f6
添加damagetypetag生成 2025-06-30 20:53:17 +08:00
17146
eff789c8af
删除冗余方法 2025-06-30 20:08:11 +08:00
17146
c4d15c32c3
魔改projectile伤害判定方法 2025-06-30 20:07:57 +08:00
17146
24a24e2243
添加全局鼠标灵敏度配置 2025-06-30 19:40:44 +08:00
49 changed files with 684 additions and 514 deletions

View file

@ -1,5 +1,4 @@
{
"replace": false,
"values": [
"superbwarfare:projectile_boom",
"superbwarfare:custom_explosion",

View file

@ -1,5 +1,4 @@
{
"replace": false,
"values": [
"superbwarfare:gunfire_absolute",
"superbwarfare:gunfire_headshot_absolute",
@ -7,9 +6,9 @@
"superbwarfare:cannon_fire",
"superbwarfare:laser",
"superbwarfare:laser_headshot",
"superbwarfare:laser_static",
"superbwarfare:vehicle_strike",
"superbwarfare:vehicle_explosion",
"superbwarfare:air_crash",
"superbwarfare:laser_static"
"superbwarfare:air_crash"
]
}

View file

@ -1,5 +1,4 @@
{
"replace": false,
"values": [
"superbwarfare:gunfire_absolute",
"superbwarfare:gunfire_headshot_absolute",
@ -7,9 +6,9 @@
"superbwarfare:cannon_fire",
"superbwarfare:laser",
"superbwarfare:laser_headshot",
"superbwarfare:laser_static",
"superbwarfare:vehicle_strike",
"superbwarfare:air_crash",
"superbwarfare:vehicle_explosion",
"superbwarfare:laser_static"
"superbwarfare:air_crash"
]
}

View file

@ -1,5 +1,4 @@
{
"replace": false,
"values": [
"superbwarfare:gunfire_absolute",
"superbwarfare:gunfire_headshot_absolute",
@ -7,9 +6,9 @@
"superbwarfare:cannon_fire",
"superbwarfare:laser",
"superbwarfare:laser_headshot",
"superbwarfare:laser_static",
"superbwarfare:vehicle_strike",
"superbwarfare:air_crash",
"superbwarfare:vehicle_explosion",
"superbwarfare:laser_static"
"superbwarfare:air_crash"
]
}

View file

@ -1,5 +1,4 @@
{
"replace": false,
"values": [
"superbwarfare:gunfire_absolute",
"superbwarfare:gunfire_headshot_absolute",
@ -7,9 +6,9 @@
"superbwarfare:cannon_fire",
"superbwarfare:laser",
"superbwarfare:laser_headshot",
"superbwarfare:laser_static",
"superbwarfare:vehicle_strike",
"superbwarfare:air_crash",
"superbwarfare:vehicle_explosion",
"superbwarfare:laser_static"
"superbwarfare:air_crash"
]
}

View file

@ -1,5 +1,4 @@
{
"replace": false,
"values": [
"superbwarfare:projectile_boom",
"superbwarfare:custom_explosion",

View file

@ -12,6 +12,7 @@ import com.atsuishio.superbwarfare.component.ModDataComponents;
import com.atsuishio.superbwarfare.config.ClientConfig;
import com.atsuishio.superbwarfare.config.CommonConfig;
import com.atsuishio.superbwarfare.config.ServerConfig;
import com.atsuishio.superbwarfare.data.CustomData;
import com.atsuishio.superbwarfare.init.*;
import com.atsuishio.superbwarfare.network.NetworkRegistry;
import net.minecraft.resources.ResourceLocation;
@ -86,6 +87,8 @@ public class Mod {
}
NeoForge.EVENT_BUS.register(this);
CustomData.load();
}
public static ResourceLocation loc(String path) {

View file

@ -4,7 +4,6 @@ package com.atsuishio.superbwarfare.client.renderer.entity;
import com.atsuishio.superbwarfare.client.model.entity.DroneModel;
import com.atsuishio.superbwarfare.entity.projectile.MortarShellEntity;
import com.atsuishio.superbwarfare.entity.projectile.RgoGrenadeEntity;
import com.atsuishio.superbwarfare.entity.projectile.RpgRocketEntity;
import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity;
import com.atsuishio.superbwarfare.init.ModEntities;
import com.atsuishio.superbwarfare.init.ModItems;
@ -19,13 +18,15 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.NotNull;
import software.bernie.geckolib.cache.object.BakedGeoModel;
import software.bernie.geckolib.cache.object.GeoBone;
import software.bernie.geckolib.renderer.GeoEntityRenderer;
import static com.atsuishio.superbwarfare.entity.vehicle.DroneEntity.KAMIKAZE_MODE;
import static com.atsuishio.superbwarfare.entity.vehicle.DroneEntity.*;
import static com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity.AMMO;
public class DroneRenderer extends GeoEntityRenderer<DroneEntity> {
@ -48,7 +49,7 @@ public class DroneRenderer extends GeoEntityRenderer<DroneEntity> {
}
@Override
public void render(DroneEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource bufferIn, int packedLightIn) {
public void render(DroneEntity entityIn, float entityYaw, float partialTicks, PoseStack poseStack, @NotNull MultiBufferSource bufferIn, int packedLightIn) {
poseStack.pushPose();
poseStack.mulPose(Axis.YP.rotationDegrees(-entityIn.getYaw(partialTicks)));
poseStack.mulPose(Axis.XP.rotationDegrees(entityIn.getBodyPitch(partialTicks)));
@ -67,12 +68,6 @@ public class DroneRenderer extends GeoEntityRenderer<DroneEntity> {
entityRenderDispatcher.render(entity, 0, 0.03, 0.25, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn);
}
if (entityIn.getEntityData().get(KAMIKAZE_MODE) == 3) {
Entity entity = new RpgRocketEntity(ModEntities.RPG_ROCKET.get(), entityIn.level());
entityRenderDispatcher.render(entity, 0, -0.03, -1.8, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn);
}
for (int i = 0; i < entityIn.getEntityData().get(AMMO); i++) {
double yOffset = 0;
double xOffset = 0;
@ -110,12 +105,54 @@ public class DroneRenderer extends GeoEntityRenderer<DroneEntity> {
entityRenderDispatcher.render(entity, xOffset, yOffset, 0, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn);
poseStack.popPose();
}
renderAttachments(entityIn, entityYaw, partialTicks, poseStack, bufferIn, packedLightIn);
}
}
poseStack.popPose();
}
private String entityNameCache = "";
private Entity entityCache = null;
// 统一渲染挂载实体
private void renderAttachments(DroneEntity entity, float entityYaw, float partialTicks, PoseStack poseStack, MultiBufferSource buffer, int packedLight) {
var attached = entity.getEntityData().get(ATTACHED_ENTITY);
if (attached.isEmpty()) return;
Entity renderEntity;
if (entityNameCache.equals(attached) && entityCache != null) {
renderEntity = entityCache;
} else {
renderEntity = EntityType.byString(attached)
.map(type -> type.create(entity.level()))
.orElse(null);
if (renderEntity == null) return;
entityNameCache = attached;
entityCache = renderEntity;
}
var displayData = entity.getEntityData().get(ATTACHMENT_DISPLAY);
var scale = new float[]{displayData.get(0), displayData.get(1), displayData.get(2)};
var offset = new float[]{displayData.get(3), displayData.get(4), displayData.get(5)};
var rotation = new float[]{displayData.get(6), displayData.get(7), displayData.get(8)};
poseStack.pushPose();
poseStack.translate(offset[0], offset[1], offset[2]);
poseStack.scale(scale[0], scale[1], scale[2]);
poseStack.mulPose(Axis.XP.rotationDegrees(rotation[0]));
poseStack.mulPose(Axis.YP.rotationDegrees(rotation[2]));
poseStack.mulPose(Axis.ZP.rotationDegrees(rotation[1]));
entityRenderDispatcher.render(renderEntity, 0, 0, 0, entityYaw, partialTicks, poseStack, buffer, packedLight);
poseStack.popPose();
}
@Override
public void renderRecursively(PoseStack poseStack, DroneEntity animatable, GeoBone bone, RenderType renderType, MultiBufferSource bufferSource, VertexConsumer buffer, boolean isReRender, float partialTick, int packedLight, int packedOverlay, int color) {
String name = bone.getName();
@ -134,24 +171,6 @@ public class DroneRenderer extends GeoEntityRenderer<DroneEntity> {
}
}
if (name.equals("c4")) {
bone.setHidden(animatable.getEntityData().get(KAMIKAZE_MODE) != 2);
}
// Player player = Minecraft.getInstance().player;
// if (player != null && animatable.getEntityData().get(KAMIKAZE_MODE) == 2 && name.equals("c4")) {
// ItemStack stack = player.getMainHandItem();
// DroneEntity drone = EntityFindUtil.findDrone(player.level(), stack.getOrCreateTag().getString("LinkedDrone"));
//
// if (!(stack.is(ModItems.MONITOR.get()) && stack.getOrCreateTag().getBoolean("Using") && stack.getOrCreateTag().getBoolean("Linked") && drone != null && drone.getUUID() == animatable.getUUID())) {
// bone.setHidden(true);
// } else {
// bone.setHidden(false);
// }
// }
super.renderRecursively(poseStack, animatable, bone, renderType, bufferSource, buffer, isReRender, partialTick, packedLight, packedOverlay, color);
}
}

View file

@ -1,9 +1,9 @@
package com.atsuishio.superbwarfare.compat.clothconfig;
import com.atsuishio.superbwarfare.compat.clothconfig.client.ControlClothConfig;
import com.atsuishio.superbwarfare.compat.clothconfig.client.DisplayClothConfig;
import com.atsuishio.superbwarfare.compat.clothconfig.client.KillMessageClothConfig;
import com.atsuishio.superbwarfare.compat.clothconfig.client.ReloadClothConfig;
import com.atsuishio.superbwarfare.compat.clothconfig.client.VehicleControlClothConfig;
import com.atsuishio.superbwarfare.compat.clothconfig.common.GameplayClothConfig;
import me.shedaniel.clothconfig2.api.ConfigBuilder;
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
@ -27,7 +27,7 @@ public class ClothConfigHelper {
ReloadClothConfig.init(root, entryBuilder);
KillMessageClothConfig.init(root, entryBuilder);
DisplayClothConfig.init(root, entryBuilder);
VehicleControlClothConfig.init(root, entryBuilder);
ControlClothConfig.init(root, entryBuilder);
GameplayClothConfig.init(root, entryBuilder);

View file

@ -0,0 +1,31 @@
package com.atsuishio.superbwarfare.compat.clothconfig.client;
import com.atsuishio.superbwarfare.config.client.ControlConfig;
import me.shedaniel.clothconfig2.api.ConfigBuilder;
import me.shedaniel.clothconfig2.api.ConfigCategory;
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
import net.minecraft.network.chat.Component;
import static com.atsuishio.superbwarfare.compat.clothconfig.ClothConfigHelper.save;
public class ControlClothConfig {
public static void init(ConfigBuilder root, ConfigEntryBuilder entryBuilder) {
ConfigCategory category = root.getOrCreateCategory(Component.translatable("config.superbwarfare.client.control"));
category.addEntry(entryBuilder
.startBooleanToggle(Component.translatable("config.superbwarfare.client.control.invert_aircraft_control"), ControlConfig.INVERT_AIRCRAFT_CONTROL.get())
.setDefaultValue(true)
.setSaveConsumer(save(ControlConfig.INVERT_AIRCRAFT_CONTROL))
.setTooltip(Component.translatable("config.superbwarfare.client.control.invert_aircraft_control.des")).build()
);
category.addEntry(entryBuilder
.startIntSlider(Component.translatable("config.superbwarfare.client.control.mouse_sensitivity"), ControlConfig.MOUSE_SENSITIVITY.get(),
10, 200)
.setDefaultValue(100)
.setSaveConsumer(save(ControlConfig.MOUSE_SENSITIVITY))
.setTooltip(Component.translatable("config.superbwarfare.client.control.mouse_sensitivity.des")).build()
);
}
}

View file

@ -1,23 +0,0 @@
package com.atsuishio.superbwarfare.compat.clothconfig.client;
import com.atsuishio.superbwarfare.config.client.VehicleControlConfig;
import me.shedaniel.clothconfig2.api.ConfigBuilder;
import me.shedaniel.clothconfig2.api.ConfigCategory;
import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
import net.minecraft.network.chat.Component;
import static com.atsuishio.superbwarfare.compat.clothconfig.ClothConfigHelper.save;
public class VehicleControlClothConfig {
public static void init(ConfigBuilder root, ConfigEntryBuilder entryBuilder) {
ConfigCategory category = root.getOrCreateCategory(Component.translatable("config.superbwarfare.client.vehicle"));
category.addEntry(entryBuilder
.startBooleanToggle(Component.translatable("config.superbwarfare.client.vehicle.invert_aircraft_control"), VehicleControlConfig.INVERT_AIRCRAFT_CONTROL.get())
.setDefaultValue(true)
.setSaveConsumer(save(VehicleControlConfig.INVERT_AIRCRAFT_CONTROL))
.setTooltip(Component.translatable("config.superbwarfare.client.vehicle.left_click_reload.des")).build()
);
}
}

View file

@ -11,7 +11,7 @@ public class ClientConfig {
ReloadConfig.init(builder);
KillMessageConfig.init(builder);
DisplayConfig.init(builder);
VehicleControlConfig.init(builder);
ControlConfig.init(builder);
EnvironmentChecksumConfig.init(builder);
return builder.build();

View file

@ -2,16 +2,20 @@ package com.atsuishio.superbwarfare.config.client;
import net.neoforged.neoforge.common.ModConfigSpec;
public class VehicleControlConfig {
public class ControlConfig {
public static ModConfigSpec.BooleanValue INVERT_AIRCRAFT_CONTROL;
public static ModConfigSpec.IntValue MOUSE_SENSITIVITY;
public static void init(ModConfigSpec.Builder builder) {
builder.push("invert_aircraft_control");
builder.push("control");
builder.comment("Set true to invert aircraft control");
INVERT_AIRCRAFT_CONTROL = builder.define("invert_aircraft_control", false);
builder.comment("Sensitivity of mouse");
MOUSE_SENSITIVITY = builder.defineInRange("mouse_sensitivity", 100, 10, 200);
builder.pop();
}
}

View file

@ -0,0 +1,19 @@
package com.atsuishio.superbwarfare.data;
import com.atsuishio.superbwarfare.data.drone_attachment.DroneAttachmentData;
import com.atsuishio.superbwarfare.data.gun.DefaultGunData;
import com.atsuishio.superbwarfare.data.gun.GunData;
import com.atsuishio.superbwarfare.data.gun.ProjectileInfo;
import com.atsuishio.superbwarfare.data.vehicle.DefaultVehicleData;
import com.atsuishio.superbwarfare.data.vehicle.VehicleData;
public class CustomData {
public static final DataLoader.DataMap<ProjectileInfo> LAUNCHABLE_ENTITY = DataLoader.createData("launchable", ProjectileInfo.class);
public static final DataLoader.DataMap<DefaultVehicleData> VEHICLE = DataLoader.createData("vehicles", DefaultVehicleData.class, map -> VehicleData.dataCache.invalidateAll());
public static final DataLoader.DataMap<DefaultGunData> GUN = DataLoader.createData("guns", DefaultGunData.class, map -> GunData.dataCache.invalidateAll());
public static final DataLoader.DataMap<DroneAttachmentData> DRONE_ATTACHMENT = DataLoader.createData("drone_attachments", DroneAttachmentData.class);
// 务必在Mod加载时调用该方法确保上面的静态数据加载成功
public static void load() {
}
}

View file

@ -0,0 +1,176 @@
package com.atsuishio.superbwarfare.data;
import com.atsuishio.superbwarfare.Mod;
import com.google.gson.Gson;
import net.minecraft.server.packs.resources.ResourceManager;
import net.neoforged.bus.api.EventPriority;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.OnDatapackSyncEvent;
import net.neoforged.neoforge.event.server.ServerStartedEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.InputStreamReader;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@EventBusSubscriber(modid = Mod.MODID)
public class DataLoader {
private static final HashMap<String, GeneralData<?>> loadedData = new HashMap<>();
private record GeneralData<T extends IDBasedData>(
Class<?> type, DataMap<T> proxyMap,
HashMap<String, Object> data,
@Nullable Consumer<Map<String, Object>> onReload
) {
}
public static <T extends IDBasedData> DataMap<T> createData(String name, Class<T> clazz) {
return createData(name, clazz, null);
}
@SuppressWarnings("unchecked")
public static <T extends IDBasedData> DataMap<T> createData(String name, Class<T> clazz, @Nullable Consumer<Map<String, Object>> onReload) {
if (loadedData.containsKey(name)) {
return (DataMap<T>) loadedData.get(name).proxyMap;
} else {
var proxyMap = new DataMap<T>(name);
loadedData.put(name, new GeneralData<>(clazz, proxyMap, new HashMap<>(), onReload));
return proxyMap;
}
}
private static void reloadAllData(ResourceManager manager) {
loadedData.forEach((name, value) -> {
var map = value.data;
map.clear();
for (var entry : manager.listResources(name, file -> file.getPath().endsWith(".json")).entrySet()) {
var attribute = entry.getValue();
try {
Gson gson = new Gson();
var data = (IDBasedData) gson.fromJson(new InputStreamReader(attribute.open()), value.type);
String id;
if (!data.getId().isEmpty()) {
id = data.getId();
} else {
var path = entry.getKey().getPath();
id = Mod.MODID + ":" + path.substring(name.length() + 1, path.length() - name.length() - 1);
Mod.LOGGER.warn("{} ID for {} is empty, try using {} as id", name, id, path);
}
map.put(id, data);
} catch (Exception e) {
Mod.LOGGER.error(e.getMessage());
}
}
if (value.onReload != null) {
value.onReload.accept(map);
}
});
}
@SubscribeEvent(priority = EventPriority.HIGH)
public static void serverStarted(ServerStartedEvent event) {
reloadAllData(event.getServer().getResourceManager());
}
@SubscribeEvent(priority = EventPriority.HIGH)
public static void onDataPackSync(OnDatapackSyncEvent event) {
reloadAllData(event.getPlayerList().getServer().getResourceManager());
}
// read-only custom data map
public static class DataMap<T extends IDBasedData> extends HashMap<String, T> {
private final String name;
private DataMap(String name) {
this.name = name;
}
@Override
public int size() {
if (!loadedData.containsKey(name)) return 0;
return loadedData.get(name).data.size();
}
@Override
public boolean isEmpty() {
if (!loadedData.containsKey(name)) return true;
return loadedData.get(name).data.isEmpty();
}
@Override
@SuppressWarnings("unchecked")
public T get(Object key) {
if (!loadedData.containsKey(name)) return null;
return (T) loadedData.get(name).data.get(key);
}
@Override
public T getOrDefault(Object key, T defaultValue) {
var value = get(key);
return value == null ? defaultValue : value;
}
@Override
public boolean containsKey(Object key) {
if (!loadedData.containsKey(name)) return false;
return loadedData.get(name).data.containsKey(key);
}
@Override
public T put(String key, T value) {
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map<? extends String, ? extends T> m) {
throw new UnsupportedOperationException();
}
@Override
public T remove(Object key) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean containsValue(Object value) {
if (!loadedData.containsKey(name)) return false;
return loadedData.get(name).data.containsValue(value);
}
@Override
public @NotNull Set<String> keySet() {
if (!loadedData.containsKey(name)) return Set.of();
return loadedData.get(name).data.keySet();
}
@Override
@SuppressWarnings("unchecked")
public @NotNull Collection<T> values() {
if (!loadedData.containsKey(name)) return Set.of();
return loadedData.get(name).data.values().stream().map(v -> (T) v).toList();
}
@Override
@SuppressWarnings("unchecked")
public @NotNull Set<Entry<String, T>> entrySet() {
if (!loadedData.containsKey(name)) return Set.of();
return loadedData.get(name).data.entrySet().stream()
.map(e -> new AbstractMap.SimpleImmutableEntry<>(e.getKey(), (T) e.getValue()))
.collect(Collectors.toCollection(HashSet::new));
}
}
}

View file

@ -0,0 +1,5 @@
package com.atsuishio.superbwarfare.data;
public interface IDBasedData {
String getId();
}

View file

@ -0,0 +1,65 @@
package com.atsuishio.superbwarfare.data.drone_attachment;
import com.atsuishio.superbwarfare.data.IDBasedData;
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;
public class DroneAttachmentData implements IDBasedData {
@SerializedName("ItemID")
public String itemID = "";
@SerializedName("EntityID")
public String entityID = "";
@Override
public String getId() {
return this.itemID;
}
@SerializedName("Count")
private int count = 1;
public int count() {
return Math.min(1, this.count);
}
@SerializedName("IsKamikaze")
public boolean isKamikaze = true;
@SerializedName("HitDamage")
public float hitDamage = 0;
@SerializedName("ExplosionDamage")
public float explosionDamage = 0;
@SerializedName("ExplosionRadius")
public float explosionRadius = 0;
// TODO 其他挂载设置
// display settings
@SerializedName("Scale")
private float[] scale = new float[]{1, 1, 1};
@SerializedName("Offset")
private float[] offset = new float[]{0, 0, 0};
@SerializedName("Rotation")
private float[] rotation = new float[]{0, 0, 0};
public float[] scale() {
return (this.scale != null && this.scale.length < 3) ? new float[]{1, 1, 1} : this.scale;
}
public float[] offset() {
return (this.offset != null && this.offset.length < 3) ? new float[]{0, 0, 0} : this.offset;
}
public float[] rotation() {
return (this.rotation != null && this.rotation.length < 3) ? new float[]{0, 0, 0} : this.rotation;
}
@SerializedName("Data")
public JsonObject data;
}

View file

@ -1,15 +1,21 @@
package com.atsuishio.superbwarfare.data.gun;
import com.atsuishio.superbwarfare.annotation.ServerOnly;
import com.atsuishio.superbwarfare.data.IDBasedData;
import com.google.gson.annotations.SerializedName;
import java.util.List;
import java.util.Set;
public class DefaultGunData {
public class DefaultGunData implements IDBasedData {
@SerializedName("ID")
public String id = "";
@Override
public String getId() {
return this.id;
}
@SerializedName("RecoilX")
public double recoilX;
@SerializedName("RecoilY")

View file

@ -1,13 +1,19 @@
package com.atsuishio.superbwarfare.data.gun;
import com.atsuishio.superbwarfare.data.IDBasedData;
import com.google.gson.JsonObject;
import com.google.gson.annotations.SerializedName;
public class ProjectileInfo {
public class ProjectileInfo implements IDBasedData {
@SerializedName("Type")
public String type = "superbwarfare:projectile";
@SerializedName("Data")
public JsonObject data;
@Override
public String getId() {
return type;
}
}

View file

@ -1,51 +1,24 @@
package com.atsuishio.superbwarfare.data.launchable;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.data.CustomData;
import com.atsuishio.superbwarfare.data.gun.ProjectileInfo;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import net.minecraft.nbt.*;
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.server.ServerStartedEvent;
import org.jetbrains.annotations.Nullable;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
@EventBusSubscriber(modid = Mod.MODID)
public class LaunchableEntityTool {
public static HashMap<String, JsonObject> launchableEntitiesData = new HashMap<>();
/**
* 初始化数据从data中读取数据json文件
*/
public static void initJsonData(ResourceManager manager) {
launchableEntitiesData.clear();
for (var entry : manager.listResources("launchable", file -> file.getPath().endsWith(".json")).entrySet()) {
var attribute = entry.getValue();
try {
Gson gson = new Gson();
var data = gson.fromJson(new InputStreamReader(attribute.open()), JsonObject.class);
launchableEntitiesData.put(data.get("Type").getAsString(), data.get("Data").getAsJsonObject());
} catch (Exception e) {
Mod.LOGGER.error(e.getMessage());
}
}
}
public static Map<String, ProjectileInfo> launchableEntitiesData = CustomData.LAUNCHABLE_ENTITY;
public static @Nullable CompoundTag getModifiedTag(ProjectileInfo projectileInfo, ShootData data) {
JsonObject launchableData;
if (projectileInfo.data != null) {
launchableData = projectileInfo.data;
} else if (launchableEntitiesData.containsKey(projectileInfo.type)) {
launchableData = launchableEntitiesData.get(projectileInfo.type);
launchableData = launchableEntitiesData.get(projectileInfo.type).data;
} else {
return null;
}
@ -104,14 +77,4 @@ public class LaunchableEntityTool {
default -> StringTag.valueOf(value);
};
}
@SubscribeEvent
public static void serverStarted(ServerStartedEvent event) {
initJsonData(event.getServer().getResourceManager());
}
@SubscribeEvent
public static void onDataPackSync(OnDatapackSyncEvent event) {
initJsonData(event.getPlayerList().getServer().getResourceManager());
}
}

View file

@ -2,15 +2,21 @@ package com.atsuishio.superbwarfare.data.vehicle;
import com.atsuishio.superbwarfare.annotation.ServerOnly;
import com.atsuishio.superbwarfare.config.server.VehicleConfig;
import com.atsuishio.superbwarfare.data.IDBasedData;
import com.atsuishio.superbwarfare.entity.vehicle.damage.DamageModify;
import com.google.gson.annotations.SerializedName;
import java.util.List;
public class DefaultVehicleData {
public class DefaultVehicleData implements IDBasedData {
@SerializedName("ID")
public String id = "";
@Override
public String getId() {
return this.id;
}
@SerializedName("MaxHealth")
public float maxHealth = 50;

View file

@ -1,55 +1,21 @@
package com.atsuishio.superbwarfare.data.vehicle;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.data.CustomData;
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;
@EventBusSubscriber(modid = Mod.MODID)
public class VehicleDataTool {
public static HashMap<String, DefaultVehicleData> vehicleData = new HashMap<>();
public static final String VEHICLE_DATA_FOLDER = "vehicles";
public static void initJsonData(ResourceManager manager) {
vehicleData.clear();
VehicleData.dataCache.invalidateAll();
for (var entry : manager.listResources(VEHICLE_DATA_FOLDER, file -> file.getPath().endsWith(".json")).entrySet()) {
var attribute = entry.getValue();
try {
Gson gson = new Gson();
var data = gson.fromJson(new InputStreamReader(attribute.open()), DefaultVehicleData.class);
String id;
if (!data.id.isEmpty()) {
id = data.id;
} else {
var path = entry.getKey().getPath();
id = Mod.MODID + ":" + path.substring(VEHICLE_DATA_FOLDER.length() + 1, path.length() - VEHICLE_DATA_FOLDER.length() - 1);
Mod.LOGGER.warn("Vehicle ID for {} is empty, try using {} as id", id, path);
data.id = id;
}
if (!vehicleData.containsKey(id)) {
vehicleData.put(id, data);
}
} catch (Exception e) {
Mod.LOGGER.error(e.getMessage());
}
}
}
public static HashMap<String, DefaultVehicleData> vehicleData = CustomData.VEHICLE;
@SubscribeEvent
public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) {
@ -63,15 +29,9 @@ public class VehicleDataTool {
}
}
@SubscribeEvent
public static void serverStarted(ServerStartedEvent event) {
initJsonData(event.getServer().getResourceManager());
}
@SubscribeEvent
public static void onDataPackSync(OnDatapackSyncEvent event) {
var server = event.getPlayerList().getServer();
initJsonData(server.getResourceManager());
var message = VehiclesDataMessage.create();
for (var player : event.getRelevantPlayers().toList()) {

View file

@ -7,6 +7,7 @@ import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.data.tags.DamageTypeTagsProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.DamageTypeTags;
import net.minecraft.world.damagesource.DamageTypes;
import net.neoforged.neoforge.common.data.ExistingFileHelper;
import org.jetbrains.annotations.NotNull;
@ -39,5 +40,22 @@ public class ModDamageTypeTagProvider extends DamageTypeTagsProvider {
.addOptional(ResourceLocation.fromNamespaceAndPath("sona", "injury"));
this.tag(ModTags.DamageTypes.VEHICLE_NOT_ABSORB)
.add(DamageTypes.EXPLOSION, DamageTypes.PLAYER_EXPLOSION, ModDamageTypes.CUSTOM_EXPLOSION, ModDamageTypes.MINE, ModDamageTypes.PROJECTILE_BOOM);
this.tag(DamageTypeTags.ALWAYS_HURTS_ENDER_DRAGONS).add(ModDamageTypes.PROJECTILE_BOOM, ModDamageTypes.CUSTOM_EXPLOSION,
ModDamageTypes.CANNON_FIRE, ModDamageTypes.LASER, ModDamageTypes.LASER_HEADSHOT, ModDamageTypes.LASER_STATIC);
this.tag(DamageTypeTags.BYPASSES_ARMOR).add(ModDamageTypes.GUN_FIRE_ABSOLUTE, ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE,
ModDamageTypes.SHOCK, ModDamageTypes.CANNON_FIRE, ModDamageTypes.LASER, ModDamageTypes.LASER_HEADSHOT, ModDamageTypes.LASER_STATIC,
ModDamageTypes.VEHICLE_STRIKE, ModDamageTypes.VEHICLE_EXPLOSION, ModDamageTypes.AIR_CRASH);
this.tag(DamageTypeTags.BYPASSES_EFFECTS).add(ModDamageTypes.GUN_FIRE_ABSOLUTE, ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE,
ModDamageTypes.SHOCK, ModDamageTypes.CANNON_FIRE, ModDamageTypes.LASER, ModDamageTypes.LASER_HEADSHOT, ModDamageTypes.LASER_STATIC,
ModDamageTypes.VEHICLE_STRIKE, ModDamageTypes.VEHICLE_EXPLOSION, ModDamageTypes.AIR_CRASH);
this.tag(DamageTypeTags.BYPASSES_ENCHANTMENTS).add(ModDamageTypes.GUN_FIRE_ABSOLUTE, ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE,
ModDamageTypes.SHOCK, ModDamageTypes.CANNON_FIRE, ModDamageTypes.LASER, ModDamageTypes.LASER_HEADSHOT, ModDamageTypes.LASER_STATIC,
ModDamageTypes.VEHICLE_STRIKE, ModDamageTypes.VEHICLE_EXPLOSION, ModDamageTypes.AIR_CRASH);
this.tag(DamageTypeTags.BYPASSES_RESISTANCE).add(ModDamageTypes.GUN_FIRE_ABSOLUTE, ModDamageTypes.GUN_FIRE_HEADSHOT_ABSOLUTE,
ModDamageTypes.SHOCK, ModDamageTypes.CANNON_FIRE, ModDamageTypes.LASER, ModDamageTypes.LASER_HEADSHOT, ModDamageTypes.LASER_STATIC,
ModDamageTypes.VEHICLE_STRIKE, ModDamageTypes.VEHICLE_EXPLOSION, ModDamageTypes.AIR_CRASH);
this.tag(DamageTypeTags.IS_EXPLOSION).add(ModDamageTypes.PROJECTILE_BOOM, ModDamageTypes.CUSTOM_EXPLOSION, ModDamageTypes.LUNGE_MINE);
this.tag(DamageTypeTags.IS_FIRE).add(ModDamageTypes.BURN);
}
}

View file

@ -21,8 +21,6 @@ import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.particles.BlockParticleOption;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundSoundPacket;
import net.minecraft.network.syncher.EntityDataAccessor;
@ -39,11 +37,8 @@ import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.monster.Monster;
import net.minecraft.world.entity.monster.Ravager;
import net.minecraft.world.entity.monster.Vex;
import net.minecraft.world.entity.monster.Witch;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.ItemStack;
@ -55,7 +50,6 @@ import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.*;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.neoforged.neoforge.common.Tags;
import net.neoforged.neoforge.entity.IEntityWithComplexSpawn;
import net.neoforged.neoforge.entity.PartEntity;
import net.neoforged.neoforge.event.EventHooks;
import net.neoforged.neoforge.network.PacketDistributor;
@ -74,7 +68,7 @@ import java.util.function.Predicate;
import static com.atsuishio.superbwarfare.tools.ParticleTool.sendParticle;
@SuppressWarnings({"unused", "UnusedReturnValue", "SuspiciousNameCombination"})
public class ProjectileEntity extends Projectile implements IEntityWithComplexSpawn, GeoEntity, CustomSyncMotionEntity {
public class ProjectileEntity extends Projectile implements GeoEntity, CustomSyncMotionEntity {
public static final EntityDataAccessor<Float> COLOR_R = SynchedEntityData.defineId(ProjectileEntity.class, EntityDataSerializers.FLOAT);
public static final EntityDataAccessor<Float> COLOR_G = SynchedEntityData.defineId(ProjectileEntity.class, EntityDataSerializers.FLOAT);
@ -98,15 +92,10 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
protected int shooterId;
private float damage = 1f;
private float headShot = 1f;
private float monsterMultiplier = 0.0f;
private float legShot = 0.5f;
private boolean beast = false;
private boolean zoom = false;
private float bypassArmorRate = 0.0f;
private float undeadMultiple = 1.0f;
private float illagerMultiple = 1.0f;
private int riotLevel = 0;
private int jhpLevel = 0;
private int heLevel = 0;
private int fireLevel = 0;
private boolean dragonBreath = false;
@ -115,6 +104,12 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
private final ArrayList<MobEffectInstance> mobEffects = new ArrayList<>();
private String gunItemId;
public static final Predicate<Entity> MONSTER_PREDICATE = entity -> entity instanceof Monster;
public static final Predicate<Entity> UNDEAD_PREDICATE = entity -> entity.getType().is(EntityTypeTags.UNDEAD);
public static final Predicate<Entity> RAIDERS_PREDICATE = entity -> entity.getType().is(EntityTypeTags.RAIDERS) || entity instanceof Vex;
private final Map<Predicate<Entity>, Float> damageModifiers = new HashMap<>(Map.of(MONSTER_PREDICATE, 1.0f));
public ProjectileEntity(EntityType<? extends ProjectileEntity> entityType, Level level) {
super(entityType, level);
this.noCulling = true;
@ -260,7 +255,7 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
}
if (heLevel > 0) {
explosionBullet(this, this.damage, heLevel, monsterMultiplier + 1, hitPos);
explosionBullet(this, this.damage, heLevel, this.damageModifiers.get(MONSTER_PREDICATE), hitPos);
}
return new EntityResult(entity, hitPos, headshot, legShot);
@ -350,44 +345,6 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
}
}
@Override
protected void readAdditionalSaveData(CompoundTag tag) {
this.damage = tag.getFloat("Damage");
this.headShot = tag.getFloat("HeadShot");
this.monsterMultiplier = tag.getFloat("MonsterMultiplier");
this.legShot = tag.getFloat("LegShot");
this.bypassArmorRate = tag.getFloat("BypassArmorRate");
this.undeadMultiple = tag.getFloat("UndeadMultiple");
this.illagerMultiple = tag.getFloat("IllagerMultiple");
this.knockback = tag.getFloat("Knockback");
this.beast = tag.getBoolean("Beast");
this.forceKnockback = tag.getBoolean("ForceKnockback");
if (tag.contains("GunId")) {
this.gunItemId = tag.getString("GunId");
}
}
@Override
protected void addAdditionalSaveData(CompoundTag tag) {
tag.putFloat("Damage", this.damage);
tag.putFloat("HeadShot", this.headShot);
tag.putFloat("MonsterMultiplier", this.monsterMultiplier);
tag.putFloat("LegShot", this.legShot);
tag.putFloat("BypassArmorRate", this.bypassArmorRate);
tag.putFloat("UndeadMultiple", this.undeadMultiple);
tag.putFloat("IllagerMultiple", this.illagerMultiple);
tag.putFloat("Knockback", this.knockback);
tag.putBoolean("Beast", this.beast);
tag.putBoolean("ForceKnockback", this.forceKnockback);
if (this.gunItemId != null) {
tag.putString("GunId", this.gunItemId);
}
}
@Override
protected void onHit(@Nullable HitResult result) {
if (result instanceof BlockHitResult blockHitResult) {
@ -420,7 +377,7 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
this.onHitBlock(hitVec, blockHitResult);
if (heLevel > 0) {
explosionBullet(this, this.damage, heLevel, monsterMultiplier + 1, hitVec);
explosionBullet(this, this.damage, heLevel, this.damageModifiers.get(MONSTER_PREDICATE), hitVec);
}
if (fireLevel > 0 && this.level() instanceof ServerLevel serverLevel) {
ParticleTool.sendParticle(serverLevel, ParticleTypes.LAVA, hitVec.x, hitVec.y, hitVec.z,
@ -533,8 +490,6 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
protected void onHitEntity(Entity entity, boolean headshot, boolean legShot) {
if (this.shooter == null) return;
float mMultiple = 1 + this.monsterMultiplier;
if (entity == null) return;
if (entity instanceof PartEntity<?> part) {
@ -542,38 +497,17 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
}
if (entity instanceof LivingEntity living) {
living.level().playSound(null, living.getOnPos(), ModSounds.MELEE_HIT.get(), SoundSource.PLAYERS, 1, (float) ((2 * org.joml.Math.random() - 1) * 0.1f + 1.0f));
living.level().playSound(null, living.getOnPos(), ModSounds.MELEE_HIT.get(), SoundSource.PLAYERS, 1, (float) (2 * Math.random() - 1) * 0.1f + 1.0f);
if (beast) {
Beast.beastKill(this.shooter, living);
return;
}
}
if (beast && entity instanceof LivingEntity living) {
Beast.beastKill(this.shooter, living);
return;
}
if (entity instanceof Monster) {
this.damage *= mMultiple;
}
if (entity instanceof LivingEntity living && living.getType().is(EntityTypeTags.UNDEAD)) {
this.damage *= this.undeadMultiple;
}
if (entity instanceof LivingEntity living && (living.getType().is(EntityTypeTags.ILLAGER) || living instanceof Vex || living instanceof Ravager || living instanceof Witch)) {
this.damage *= this.illagerMultiple;
}
if (entity instanceof LivingEntity living && riotLevel > 0 && !entity.level().isClientSide()) {
living.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, 20 + riotLevel * 10, (int) (riotLevel * 0.25), false, false), this.shooter);
living.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, 20 + riotLevel * 10, (int) (riotLevel * 0.25), false, false), this.shooter);
}
if (entity instanceof LivingEntity living && jhpLevel > 0) {
this.damage *= (1.0f + 0.12f * jhpLevel) * ((float) (10 / (living.getAttributeValue(Attributes.ARMOR) + 10)) + 0.25f);
}
if (fireLevel > 0) {
if (!entity.level().isClientSide() && entity instanceof LivingEntity living) {
living.addEffect(new MobEffectInstance(ModMobEffects.BURN, 60 + fireLevel * 20, fireLevel, false, false), this.shooter);
for (var entry : this.damageModifiers.entrySet()) {
if (entry.getKey().test(entity)) {
this.damage *= entry.getValue();
}
}
@ -787,15 +721,6 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
}
}
@Override
public void readSpawnData(@NotNull RegistryFriendlyByteBuf additionalData) {
}
@Override
public void writeSpawnData(@NotNull RegistryFriendlyByteBuf buffer) {
}
public static class EntityResult {
private final Entity entity;
private final Vec3 hitVec;
@ -853,6 +778,10 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
return this.gunItemId;
}
public Map<Predicate<Entity>, Float> getDamageModifiers() {
return damageModifiers;
}
/**
* Builders
*/
@ -871,11 +800,6 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
return this;
}
public ProjectileEntity setMonsterMultiplier(float monsterMultiplier) {
this.monsterMultiplier = monsterMultiplier;
return this;
}
public ProjectileEntity legShot(float legShot) {
this.legShot = legShot;
return this;
@ -886,16 +810,6 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
return this;
}
public ProjectileEntity riotBullet(int riotLevel) {
this.riotLevel = riotLevel;
return this;
}
public ProjectileEntity jhpBullet(int jhpLevel) {
this.jhpLevel = jhpLevel;
return this;
}
public ProjectileEntity heBullet(int heLevel) {
this.heLevel = heLevel;
return this;
@ -917,16 +831,6 @@ public class ProjectileEntity extends Projectile implements IEntityWithComplexSp
return this;
}
public ProjectileEntity undeadMultiple(float undeadMultiple) {
this.undeadMultiple = undeadMultiple;
return this;
}
public ProjectileEntity illagerMultiple(float illagerMultiple) {
this.illagerMultiple = illagerMultiple;
return this;
}
public ProjectileEntity effect(ArrayList<MobEffectInstance> mobEffectInstances) {
this.mobEffects.addAll(mobEffectInstances);
return this;

View file

@ -1,12 +1,10 @@
package com.atsuishio.superbwarfare.entity.vehicle;
import com.atsuishio.superbwarfare.config.server.ExplosionConfig;
import com.atsuishio.superbwarfare.data.CustomData;
import com.atsuishio.superbwarfare.entity.projectile.*;
import com.atsuishio.superbwarfare.entity.vehicle.base.MobileVehicleEntity;
import com.atsuishio.superbwarfare.init.ModDamageTypes;
import com.atsuishio.superbwarfare.init.ModItems;
import com.atsuishio.superbwarfare.init.ModSounds;
import com.atsuishio.superbwarfare.init.ModTags;
import com.atsuishio.superbwarfare.init.*;
import com.atsuishio.superbwarfare.item.Monitor;
import com.atsuishio.superbwarfare.item.common.ammo.MortarShell;
import com.atsuishio.superbwarfare.tools.CustomExplosion;
@ -57,6 +55,7 @@ import software.bernie.geckolib.animation.AnimatableManager;
import software.bernie.geckolib.util.GeckoLibUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
@ -66,6 +65,10 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
public static final EntityDataAccessor<String> CONTROLLER = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.STRING);
public static final EntityDataAccessor<Integer> KAMIKAZE_MODE = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.INT);
public static final EntityDataAccessor<Float> DELTA_X_ROT = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.FLOAT);
public static final EntityDataAccessor<String> ATTACHED_ENTITY = SynchedEntityData.defineId(DroneEntity.class, EntityDataSerializers.STRING);
// scale[3], offset[3], rotation[3]
public static final EntityDataAccessor<List<Float>> ATTACHMENT_DISPLAY = SynchedEntityData.defineId(DroneEntity.class, ModSerializers.FLOAT_LIST_SERIALIZER.get());
private final AnimatableInstanceCache cache = GeckoLibUtil.createInstanceCache(this);
@ -104,7 +107,9 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
builder.define(DELTA_X_ROT, 0f)
.define(CONTROLLER, "undefined")
.define(LINKED, false)
.define(KAMIKAZE_MODE, 0);
.define(KAMIKAZE_MODE, 0)
.define(ATTACHED_ENTITY, "")
.define(ATTACHMENT_DISPLAY, List.of(1f, 1f, 1f, 0f, 0f, 0f, 0f, 0f, 0f));
}
@Override
@ -286,6 +291,7 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
// 返还物品
ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(ModItems.DRONE.get()));
// TODO 返还弹药
// 返还普通弹药
for (int index0 = 0; index0 < this.entityData.get(AMMO); index0++) {
ItemHandlerHelper.giveItemToPlayer(player, new ItemStack(ModItems.RGO_GRENADE.get()));
@ -308,7 +314,7 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
this.discard();
}
} else if (stack.getItem() == ModItems.RGO_GRENADE.get() && this.entityData.get(KAMIKAZE_MODE) == 0) {
// 装载普通弹药
// TODO 清理 装载普通弹药
if (this.entityData.get(AMMO) < 6) {
this.entityData.set(AMMO, this.entityData.get(AMMO) + 1);
if (!player.isCreative()) {
@ -319,7 +325,7 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
}
}
} else if (stack.getItem() instanceof MortarShell && this.entityData.get(AMMO) == 0 && this.entityData.get(KAMIKAZE_MODE) == 0) {
// 迫击炮神风
// TODO 清理 迫击炮神风
var copy = stack.copy();
copy.setCount(1);
this.currentItem = copy;
@ -332,28 +338,66 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
if (player instanceof ServerPlayer serverPlayer) {
serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1);
}
} else if (stack.getItem() == ModItems.C4_BOMB.get() && this.entityData.get(AMMO) == 0 && this.entityData.get(KAMIKAZE_MODE) == 0) {
// C4神风
this.currentItem = new ItemStack(stack.getItem(), 1);
// } else if (stack.getItem() == ModItems.C4_BOMB.get() && this.entityData.get(AMMO) == 0 && this.entityData.get(KAMIKAZE_MODE) == 0) {
// // C4神风
// this.currentItem = new ItemStack(stack.getItem(), 1);
//
// if (!player.isCreative()) {
// stack.shrink(1);
// }
// this.entityData.set(KAMIKAZE_MODE, 2);
// if (player instanceof ServerPlayer serverPlayer) {
// serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1);
// }
// } else if (stack.getItem() == ModItems.ROCKET.get() && this.entityData.get(AMMO) == 0 && this.entityData.get(KAMIKAZE_MODE) == 0) {
// // RPG神风
// this.currentItem = new ItemStack(stack.getItem(), 1);
//
// if (!player.isCreative()) {
// stack.shrink(1);
// }
// this.entityData.set(KAMIKAZE_MODE, 3);
// if (player instanceof ServerPlayer serverPlayer) {
// serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1);
// }
} else {
// 自定义挂载
var itemID = stack.getItem().toString();
var attachmentData = CustomData.DRONE_ATTACHMENT.get(itemID);
if (!player.isCreative()) {
stack.shrink(1);
}
this.entityData.set(KAMIKAZE_MODE, 2);
if (player instanceof ServerPlayer serverPlayer) {
serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1);
}
} else if (stack.getItem() == ModItems.ROCKET.get() && this.entityData.get(AMMO) == 0 && this.entityData.get(KAMIKAZE_MODE) == 0) {
// RPG神风
this.currentItem = new ItemStack(stack.getItem(), 1);
// 是否能挂载该物品
if (attachmentData != null && this.entityData.get(AMMO) < attachmentData.count()) {
if (this.entityData.get(ATTACHED_ENTITY).equals(attachmentData.entityID)) {
// 同种物品挂载
this.entityData.set(AMMO, this.entityData.get(AMMO) + 1);
if (!player.isCreative()) {
stack.shrink(1);
}
this.entityData.set(KAMIKAZE_MODE, 3);
if (player instanceof ServerPlayer serverPlayer) {
serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1);
if (!player.isCreative()) {
stack.shrink(1);
}
if (player instanceof ServerPlayer serverPlayer) {
serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1);
}
} else if (this.entityData.get(AMMO) == 0) {
// 不同种物品挂载
this.entityData.set(ATTACHED_ENTITY, attachmentData.entityID);
// TODO 正确处理和渲染AMMO
// this.entityData.set(AMMO, this.entityData.get(AMMO) + 1);
if (!player.isCreative()) {
stack.shrink(1);
}
if (player instanceof ServerPlayer serverPlayer) {
serverPlayer.level().playSound(null, serverPlayer.getOnPos(), ModSounds.BULLET_SUPPLY.get(), SoundSource.PLAYERS, 0.5F, 1);
}
var scale = attachmentData.scale();
var offset = attachmentData.offset();
var rotation = attachmentData.rotation();
this.entityData.set(ATTACHMENT_DISPLAY, List.of(scale[0], scale[1], scale[2], offset[0], offset[1], offset[2], rotation[0], rotation[1], rotation[2]));
}
}
}
return InteractionResult.sidedSuccess(this.level().isClientSide());
@ -457,20 +501,41 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
public void hitEntityCrash(Player player, Entity target) {
if (lastTickSpeed > 0.12) {
var attachedEntity = this.entityData.get(ATTACHED_ENTITY);
if (!attachedEntity.isEmpty() && 20 * lastTickSpeed > this.getHealth()) {
var data = CustomData.DRONE_ATTACHMENT.values().stream().filter(d -> attachedEntity.equals(d.entityID))
.findAny()
.orElse(null);
if (data != null) {
if (data.isKamikaze) {
EntityType.byString(attachedEntity).ifPresent(entityType -> {
var bomb = entityType.create(this.level());
target.hurt(ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), bomb, player), data.hitDamage);
target.invulnerableTime = 0;
});
} else {
// TODO 非神风模式
}
}
}
// TODO 清理这一坨
if (this.entityData.get(KAMIKAZE_MODE) != 0 && 20 * lastTickSpeed > this.getHealth()) {
if (this.entityData.get(KAMIKAZE_MODE) == 1) {
var mortarShell = new MortarShellEntity(player, this.level());
target.hurt(ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), mortarShell, player), ExplosionConfig.DRONE_KAMIKAZE_HIT_DAMAGE.get());
target.invulnerableTime = 0;
} else if (this.entityData.get(KAMIKAZE_MODE) == 2) {
var c4 = new C4Entity(player, this.level());
target.hurt(ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), c4, player), ExplosionConfig.DRONE_KAMIKAZE_HIT_DAMAGE_C4.get());
target.invulnerableTime = 0;
} else if (this.entityData.get(KAMIKAZE_MODE) == 3) {
var rpg = new RpgRocketEntity(player, this.level());
target.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), rpg, player), ExplosionConfig.DRONE_KAMIKAZE_HIT_DAMAGE_RPG.get());
target.invulnerableTime = 0;
}
// } else if (this.entityData.get(KAMIKAZE_MODE) == 2) {
// var c4 = new C4Entity(player, this.level());
// target.hurt(ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), c4, player), ExplosionConfig.DRONE_KAMIKAZE_HIT_DAMAGE_C4.get());
// target.invulnerableTime = 0;
// else if (this.entityData.get(KAMIKAZE_MODE) == 3) {
// var rpg = new RpgRocketEntity(player, this.level());
// target.hurt(ModDamageTypes.causeCannonFireDamage(this.level().registryAccess(), rpg, player), ExplosionConfig.DRONE_KAMIKAZE_HIT_DAMAGE_RPG.get());
// target.invulnerableTime = 0;
// }
if (player != null && player.getMainHandItem().is(ModItems.MONITOR.get())) {
var stack = player.getMainHandItem();
@ -543,8 +608,8 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
level().explode(null, this.getX(), this.getY(), this.getZ(), 0, Level.ExplosionInteraction.NONE);
}
// 神风自爆
if (this.entityData.get(KAMIKAZE_MODE) != 0) {
// TODO 清理 神风自爆
if (this.entityData.get(KAMIKAZE_MODE) != 0 || !this.entityData.get(ATTACHED_ENTITY).isEmpty()) {
kamikazeExplosion(this.entityData.get(KAMIKAZE_MODE));
}
@ -586,26 +651,50 @@ public class DroneEntity extends MobileVehicleEntity implements GeoEntity {
assert controller != null;
Entity mortarShell = new MortarShellEntity(controller, level());
Entity c4 = new C4Entity(controller, level());
Entity rpg = new RpgRocketEntity(controller, level());
// Entity c4 = new C4Entity(controller, level());
// Entity rpg = new RpgRocketEntity(controller, level());
// TODO 清理这一坨
CustomExplosion explosion = switch (mode) {
case 1 -> new CustomExplosion(this.level(), this,
ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), mortarShell, attacker), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_DAMAGE.get(),
this.getX(), this.getY(), this.getZ(), ExplosionConfig.DRONE_KAMIKAZE_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP, true).setDamageMultiplier(1);
case 2 -> new CustomExplosion(this.level(), this,
ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), c4, attacker), ExplosionConfig.C4_EXPLOSION_DAMAGE.get(),
this.getX(), this.getY(), this.getZ(), ExplosionConfig.C4_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP, true).setDamageMultiplier(1);
// case 2 -> new CustomExplosion(this.level(), this,
// ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), c4, attacker), ExplosionConfig.C4_EXPLOSION_DAMAGE.get(),
// this.getX(), this.getY(), this.getZ(), ExplosionConfig.C4_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP, true).setDamageMultiplier(1);
case 3 -> new CustomExplosion(this.level(), this,
ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), rpg, attacker), ExplosionConfig.RPG_EXPLOSION_DAMAGE.get(),
this.getX(), this.getY(), this.getZ(), ExplosionConfig.RPG_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP, true).setDamageMultiplier(1);
// case 3 -> new CustomExplosion(this.level(), this,
// ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), rpg, attacker), ExplosionConfig.RPG_EXPLOSION_DAMAGE.get(),
// this.getX(), this.getY(), this.getZ(), ExplosionConfig.RPG_EXPLOSION_RADIUS.get(), ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP, true).setDamageMultiplier(1);
default -> null;
};
if (explosion == null) return;
// 自定义实体挂载
if (explosion == null) {
var attachedEntity = this.entityData.get(ATTACHED_ENTITY);
if (attachedEntity.isEmpty()) return;
var data = CustomData.DRONE_ATTACHMENT.values().stream().filter(d -> attachedEntity.equals(d.entityID))
.findAny()
.orElse(null);
if (data == null) return;
if (data.isKamikaze) {
var bomb = EntityType.byString(attachedEntity).map(entityType ->
entityType.create(this.level())
).orElse(null);
if (bomb == null) return;
explosion = new CustomExplosion(this.level(), this,
ModDamageTypes.causeProjectileBoomDamage(this.level().registryAccess(), bomb, attacker), data.explosionDamage,
this.getX(), this.getY(), this.getZ(), data.explosionRadius, ExplosionConfig.EXPLOSION_DESTROY.get() ? Explosion.BlockInteraction.DESTROY : Explosion.BlockInteraction.KEEP, true).setDamageMultiplier(1);
} else {
// TODO 非神风自爆
return;
}
}
explosion.explode();
EventHooks.onExplosionStart(this.level(), explosion);

View file

@ -122,8 +122,14 @@ public class DamageModify {
}
return switch (sourceType) {
case TAG_KEY -> source.is(sourceTagKey);
case RESOURCE_KEY -> source.is(sourceKey);
case TAG_KEY -> {
if (sourceTagKey == null) yield false;
yield source.is(sourceTagKey);
}
case RESOURCE_KEY -> {
if (sourceKey == null) yield false;
yield source.is(sourceKey);
}
case FUNCTION -> condition.apply(source);
case ENTITY_ID -> {
var directEntity = source.getDirectEntity();
@ -141,7 +147,7 @@ public class DamageModify {
case ENTITY_TAG -> {
var directEntity = source.getDirectEntity();
if (directEntity == null) yield false;
if (entityTag == null) yield false;
yield directEntity.getType().is(entityTag);
}
case ALL -> true;

View file

@ -7,7 +7,6 @@ public class ProjectileWeapon extends VehicleWeapon {
public float headShot, damage, bypassArmorRate;
public boolean zoom;
public int jhpLevel, heLevel;
public ProjectileWeapon headShot(float headShot) {
this.headShot = headShot;
@ -34,24 +33,12 @@ public class ProjectileWeapon extends VehicleWeapon {
return this;
}
public ProjectileWeapon jhpBullet(int jhpLevel) {
this.jhpLevel = jhpLevel;
return this;
}
public ProjectileWeapon heBullet(int heLevel) {
this.heLevel = heLevel;
return this;
}
public ProjectileEntity create(LivingEntity shooter) {
return new ProjectileEntity(shooter.level())
.shooter(shooter)
.headShot(headShot)
.damage(damage)
.bypassArmorRate(bypassArmorRate)
.zoom(zoom)
.jhpBullet(jhpLevel)
.heBullet(heLevel);
.zoom(zoom);
}
}

View file

@ -1,7 +1,7 @@
package com.atsuishio.superbwarfare.event;
import com.atsuishio.superbwarfare.client.MouseMovementHandler;
import com.atsuishio.superbwarfare.config.client.VehicleControlConfig;
import com.atsuishio.superbwarfare.config.client.ControlConfig;
import com.atsuishio.superbwarfare.data.gun.GunData;
import com.atsuishio.superbwarfare.entity.vehicle.DroneEntity;
import com.atsuishio.superbwarfare.entity.vehicle.base.AirEntity;
@ -100,7 +100,7 @@ public class ClientMouseHandler {
int y = 1;
if (vehicle instanceof AirEntity && VehicleControlConfig.INVERT_AIRCRAFT_CONTROL.get()) {
if (vehicle instanceof AirEntity && ControlConfig.INVERT_AIRCRAFT_CONTROL.get()) {
y = -1;
}
@ -189,7 +189,7 @@ public class ClientMouseHandler {
if (player == null) return 1;
if (player.getVehicle() instanceof VehicleEntity vehicle && vehicle instanceof AirEntity && vehicle.getFirstPassenger() == player) {
return VehicleControlConfig.INVERT_AIRCRAFT_CONTROL.get() ? -1 : 1;
return ControlConfig.INVERT_AIRCRAFT_CONTROL.get() ? -1 : 1;
}
return 1;
}
@ -210,7 +210,7 @@ public class ClientMouseHandler {
float customSens = data.sensitivity.get();
if (!player.getMainHandItem().isEmpty() && mc.options.getCameraType() == CameraType.FIRST_PERSON) {
return original / Math.max((1 + (0.2 * (data.zoom() - (0.3 * customSens)) * ClientEventHandler.zoomTime)), 0.1);
return original / Math.max((1 + (0.2 * (data.zoom() - (0.3 * customSens)) * ClientEventHandler.zoomTime)), 0.1) * (ControlConfig.MOUSE_SENSITIVITY.get() / 100f);
}
}

View file

@ -16,4 +16,7 @@ public class ModSerializers {
public static final DeferredHolder<EntityDataSerializer<?>, EntityDataSerializer<List<Integer>>> INT_LIST_SERIALIZER = REGISTRY.register("int_list_serializer",
() -> EntityDataSerializer.forValueType(ByteBufCodecs.VAR_INT.apply(ByteBufCodecs.list()))
);
public static final DeferredHolder<EntityDataSerializer<?>, EntityDataSerializer<List<Float>>> FLOAT_LIST_SERIALIZER = REGISTRY.register("float_list_serializer",
() -> EntityDataSerializer.forValueType(ByteBufCodecs.FLOAT.apply(ByteBufCodecs.list()))
);
}

View file

@ -654,7 +654,7 @@ public abstract class GunItem extends Item implements CustomRendererItem, GeoIte
} else if (LaunchableEntityTool.launchableEntitiesData.containsKey(projectileType)) {
var newInfo = new ProjectileInfo();
newInfo.data = LaunchableEntityTool.launchableEntitiesData.get(projectileType);
newInfo.data = LaunchableEntityTool.launchableEntitiesData.get(projectileType).data;
newInfo.type = projectileType;
var tag = LaunchableEntityTool.getModifiedTag(

View file

@ -47,9 +47,10 @@ public class AmmoPerk extends Perk {
}
if (!this.mobEffects.get().isEmpty()) {
int amplifier = this.getEffectAmplifier(instance);
int duration = this.getEffectDuration(instance);
ArrayList<MobEffectInstance> mobEffectInstances = new ArrayList<>();
for (MobEffect effect : this.mobEffects.get()) {
mobEffectInstances.add(new MobEffectInstance(Holder.direct(effect), 70 + 30 * level, amplifier));
mobEffectInstances.add(new MobEffectInstance(Holder.direct(effect), duration, amplifier));
}
projectile.effect(mobEffectInstances);
}
@ -59,6 +60,10 @@ public class AmmoPerk extends Perk {
return instance.level() - 1;
}
public int getEffectDuration(PerkInstance instance) {
return 70 + 30 * instance.level();
}
public double getModifiedVelocity(GunData data, PerkInstance instance) {
return data.velocity() * this.speedRate;
}

View file

@ -2,6 +2,7 @@ package com.atsuishio.superbwarfare.perk.ammo;
import com.atsuishio.superbwarfare.data.gun.GunData;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.init.ModMobEffects;
import com.atsuishio.superbwarfare.init.ModTags;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.Perk;
@ -11,7 +12,13 @@ import net.minecraft.world.entity.Entity;
public class IncendiaryBullet extends AmmoPerk {
public IncendiaryBullet() {
super(new AmmoPerk.Builder("incendiary_bullet", Perk.Type.AMMO).bypassArmorRate(-0.4f).damageRate(0.7f).speedRate(0.75f).slug(false).rgb(230, 131, 65));
super(new AmmoPerk.Builder("incendiary_bullet", Perk.Type.AMMO).bypassArmorRate(-0.4f).damageRate(0.7f).speedRate(0.75f).slug(false).rgb(230, 131, 65)
.mobEffect(ModMobEffects.BURN));
}
@Override
public int getEffectDuration(PerkInstance instance) {
return 60 + 20 * instance.level();
}
@Override

View file

@ -1,11 +1,13 @@
package com.atsuishio.superbwarfare.perk.ammo;
import com.atsuishio.superbwarfare.data.gun.GunData;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.perk.PerkInstance;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attributes;
import org.jetbrains.annotations.Nullable;
public class JHPBullet extends AmmoPerk {
@ -14,9 +16,10 @@ public class JHPBullet extends AmmoPerk {
}
@Override
public void modifyProjectile(GunData data, PerkInstance instance, Entity entity) {
super.modifyProjectile(data, instance, entity);
if (!(entity instanceof ProjectileEntity projectile)) return;
projectile.jhpBullet(instance.level());
public float getModifiedDamage(float damage, GunData data, PerkInstance instance, @Nullable LivingEntity target, DamageSource source) {
if (target != null) {
return damage * (1.0f + 0.12f * instance.level()) * ((float) (10 / (target.getAttributeValue(Attributes.ARMOR) + 10)) + 0.25f);
}
return super.getModifiedDamage(damage, data, instance, null, source);
}
}

View file

@ -4,19 +4,30 @@ import com.atsuishio.superbwarfare.data.gun.GunData;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.PerkInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
public class RiotBullet extends AmmoPerk {
public RiotBullet() {
super(new Builder("riot_bullet", Type.AMMO).bypassArmorRate(-0.3f).damageRate(0.9f).speedRate(0.8f).slug(true).rgb(70, 35, 230));
super(new Builder("riot_bullet", Type.AMMO).bypassArmorRate(-0.3f).damageRate(0.9f).speedRate(0.8f).slug(true).rgb(70, 35, 230)
.mobEffect(MobEffects.MOVEMENT_SLOWDOWN::value).mobEffect(MobEffects.WEAKNESS::value));
}
@Override
public int getEffectAmplifier(PerkInstance instance) {
return (int) (instance.level() * 0.25);
}
@Override
public int getEffectDuration(PerkInstance instance) {
return 20 + instance.level() * 10;
}
@Override
public void modifyProjectile(GunData data, PerkInstance instance, Entity entity) {
super.modifyProjectile(data, instance, entity);
if (!(entity instanceof ProjectileEntity projectile)) return;
projectile.riotBullet(instance.level());
projectile.illagerMultiple(1.0f + 0.5f * instance.level());
projectile.getDamageModifiers().put(ProjectileEntity.RAIDERS_PREDICATE, 1.0f + 0.5f * instance.level());
}
}

View file

@ -1,7 +1,7 @@
package com.atsuishio.superbwarfare.perk.ammo;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.data.gun.GunData;
import com.atsuishio.superbwarfare.entity.projectile.ProjectileEntity;
import com.atsuishio.superbwarfare.perk.AmmoPerk;
import com.atsuishio.superbwarfare.perk.Perk;
import com.atsuishio.superbwarfare.perk.PerkInstance;
@ -17,6 +17,6 @@ public class SilverBullet extends AmmoPerk {
public void modifyProjectile(GunData data, PerkInstance instance, Entity entity) {
super.modifyProjectile(data, instance, entity);
if (!(entity instanceof ProjectileEntity projectile)) return;
projectile.undeadMultiple(1.0f + 0.5f * instance.level());
projectile.getDamageModifiers().put(ProjectileEntity.UNDEAD_PREDICATE, 1.0f + 0.5f * instance.level());
}
}

View file

@ -17,9 +17,9 @@ public class MonsterHunter extends Perk {
@Override
public void modifyProjectile(GunData data, PerkInstance instance, Entity entity) {
float multiplier = 0.1f + 0.1f * instance.level();
float multiplier = 1.1f + 0.1f * instance.level();
if (entity instanceof ProjectileEntity projectile) {
projectile.setMonsterMultiplier(multiplier);
projectile.getDamageModifiers().put(ProjectileEntity.MONSTER_PREDICATE, multiplier);
} else if (entity instanceof JavelinMissileEntity projectile) {
projectile.setMonsterMultiplier(multiplier);
} else if (entity instanceof GunGrenadeEntity projectile) {

View file

@ -1,64 +1,25 @@
package com.atsuishio.superbwarfare.tools;
import com.atsuishio.superbwarfare.Mod;
import com.atsuishio.superbwarfare.data.CustomData;
import com.atsuishio.superbwarfare.data.gun.DefaultGunData;
import com.atsuishio.superbwarfare.data.gun.GunData;
import com.atsuishio.superbwarfare.network.message.receive.GunsDataMessage;
import com.google.gson.Gson;
import net.minecraft.nbt.CompoundTag;
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 javax.annotation.Nullable;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.UUID;
@EventBusSubscriber(modid = Mod.MODID)
public class GunsTool {
public static HashMap<String, DefaultGunData> gunsData = new HashMap<>();
public static final String GUN_DATA_FOLDER = "guns";
/**
* 初始化数据从data中读取数据json文件
*/
public static void initJsonData(ResourceManager manager) {
gunsData.clear();
GunData.dataCache.invalidateAll();
for (var entry : manager.listResources(GUN_DATA_FOLDER, file -> file.getPath().endsWith(".json")).entrySet()) {
var attribute = entry.getValue();
try {
Gson gson = new Gson();
var data = gson.fromJson(new InputStreamReader(attribute.open()), DefaultGunData.class);
String id;
if (!data.id.trim().isEmpty()) {
id = data.id;
} else {
var path = entry.getKey().getPath();
id = Mod.MODID + ":" + path.substring(GUN_DATA_FOLDER.length() + 1, path.length() - GUN_DATA_FOLDER.length() - 1);
Mod.LOGGER.warn("Gun ID for {} is empty, try using {} as id", path, id);
data.id = id;
}
if (!gunsData.containsKey(id)) {
gunsData.put(id, data);
}
} catch (Exception e) {
Mod.LOGGER.error(e.getMessage());
}
}
}
public static HashMap<String, DefaultGunData> gunsData = CustomData.GUN;
@SubscribeEvent
public static void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) {
@ -72,15 +33,9 @@ public class GunsTool {
}
}
@SubscribeEvent
public static void serverStarted(ServerStartedEvent event) {
initJsonData(event.getServer().getResourceManager());
}
@SubscribeEvent
public static void onDataPackSync(OnDatapackSyncEvent event) {
var server = event.getPlayerList().getServer();
initJsonData(server.getResourceManager());
var message = GunsDataMessage.create();
for (var player : event.getRelevantPlayers().toList()) {

View file

@ -587,89 +587,6 @@
}
}
]
},
{
"name": "Weapon",
"parent": "0",
"pivot": [0, 2.2, 0]
},
{
"name": "c4",
"parent": "Weapon",
"pivot": [0.03633, 0.475, -0.41605],
"rotation": [0, -90, 180],
"cubes": [
{
"origin": [-1.42244, -0.29277, -2.10516],
"size": [4.60664, 0.92133, 3.3782],
"uv": {
"north": {"uv": [7, 3], "uv_size": [4.5, 1]},
"east": {"uv": [4, 9], "uv_size": [3.5, 1]},
"south": {"uv": [7, 4], "uv_size": [4.5, 1]},
"west": {"uv": [9, 7], "uv_size": [3.5, 1]},
"up": {"uv": [0, 0], "uv_size": [4.5, 3.5]},
"down": {"uv": [0, 7.5], "uv_size": [4.5, -3.5]}
}
},
{
"origin": [-1.11533, 0.62855, -1.79805],
"size": [0.61422, 0.30711, 2.76398],
"uv": {
"north": {"uv": [29, 25], "uv_size": [0.5, 0.25]},
"east": {"uv": [23, 2], "uv_size": [2.75, 0.25]},
"south": {"uv": [26, 29], "uv_size": [0.5, 0.25]},
"west": {"uv": [24, 0], "uv_size": [2.75, 0.25]},
"up": {"uv": [20, 0], "uv_size": [0.5, 2.75]}
}
}
]
},
{
"name": "button_group",
"parent": "c4",
"pivot": [0.11311, 0.62855, -1.49094],
"cubes": [
{
"origin": [0.11311, 0.62855, -1.49094],
"size": [2.14976, 0.30711, 2.14976],
"uv": {
"north": {"uv": [25, 22], "uv_size": [2.25, 0.25]},
"east": {"uv": [23, 25], "uv_size": [2.25, 0.25]},
"south": {"uv": [25, 23], "uv_size": [2.25, 0.25]},
"west": {"uv": [25, 24], "uv_size": [2.25, 0.25]},
"up": {"uv": [7, 0], "uv_size": [2.25, 2.25]}
}
}
]
},
{
"name": "triggers",
"parent": "c4",
"pivot": [0.72732, -0.29277, -0.56961],
"cubes": [
{
"origin": [0.11311, 0.01434, -2.41226],
"size": [1.53555, 0.30711, 0.30711],
"uv": {
"north": {"uv": [27, 11], "uv_size": [1.5, 0.25]},
"east": {"uv": [30, 4], "uv_size": [0.25, 0.25]},
"west": {"uv": [5, 30], "uv_size": [0.25, 0.25]},
"up": {"uv": [27, 12], "uv_size": [1.5, 0.25]},
"down": {"uv": [27, 13.25], "uv_size": [1.5, -0.25]}
}
},
{
"origin": [-1.11533, 0.01434, -2.41226],
"size": [0.61422, 0.30711, 0.30711],
"uv": {
"north": {"uv": [29, 26], "uv_size": [0.5, 0.25]},
"east": {"uv": [30, 5], "uv_size": [0.25, 0.25]},
"west": {"uv": [6, 30], "uv_size": [0.25, 0.25]},
"up": {"uv": [27, 29], "uv_size": [0.5, 0.25]},
"down": {"uv": [29, 27.25], "uv_size": [0.5, -0.25]}
}
}
]
}
]
}

View file

@ -627,9 +627,11 @@
"config.superbwarfare.client.display.weapon_hud_y_offset.des": "The vertical offset of weapon HUD",
"config.superbwarfare.client.display.vehicle_info": "Vehicle Info",
"config.superbwarfare.client.display.vehicle_info.des": "Whether to display vehicle info when aiming at a vehicle",
"config.superbwarfare.client.vehicle": "Control Vehicle",
"config.superbwarfare.client.vehicle.invert_aircraft_control": "Invert Aircraft Control",
"config.superbwarfare.client.vehicle.left_click_reload.des": "Set TRUE to invert aircraft control",
"config.superbwarfare.client.control": "Control Config",
"config.superbwarfare.client.control.invert_aircraft_control": "Invert Aircraft Control",
"config.superbwarfare.client.control.invert_aircraft_control.des": "Set TRUE to invert aircraft control",
"config.superbwarfare.client.control.mouse_sensitivity": "Mouse Sensitivity",
"config.superbwarfare.client.control.mouse_sensitivity.des": "Adjust mouse sensitivity while holding a gun",
"config.superbwarfare.common.gameplay": "Gameplay Config",
"config.superbwarfare.common.gameplay.respawn_reload": "Respawn Reload",

View file

@ -522,9 +522,9 @@
"config.superbwarfare.client.display.camera_rotate.des": "Visión ligeramente inestable al sostener un arma de fuego en la mano",
"config.superbwarfare.client.display.armor_plate_hud": "HUD de placas de blindaje",
"config.superbwarfare.client.display.armor_plate_hud.des": "Muestra la durabilidad del inserto antibalas equipado actualmente en la armadura pectoral en la esquina inferior izquierda cuando está activado.",
"config.superbwarfare.client.vehicle": "Vehículos de control",
"config.superbwarfare.client.vehicle.invert_aircraft_control": "Invertir el control del avión",
"config.superbwarfare.client.vehicle.left_click_reload.des": "Establece TRUE para invertir el control de la aeronave",
"config.superbwarfare.client.control": "Vehículos de control",
"config.superbwarfare.client.control.invert_aircraft_control": "Invertir el control del avión",
"config.superbwarfare.client.control.invert_aircraft_control.des": "Establece TRUE para invertir el control de la aeronave",
"config.superbwarfare.common.gameplay": "Configuración del juego",
"config.superbwarfare.common.gameplay.respawn_reload": "Recarga de Reinicio",

View file

@ -514,9 +514,9 @@
"config.superbwarfare.client.display.camera_rotate.des": "Vue légèrement secouée lorsque vous tenez une arme à feu",
"config.superbwarfare.client.display.armor_plate_hud": "HUD de la plaque d'armure",
"config.superbwarfare.client.display.armor_plate_hud.des": "Affiche la durabilité de la plaque pare-balles actuellement équipée sur l'armure de poitrine dans le coin inférieur gauche lorsqu'il est activé",
"config.superbwarfare.client.vehicle": "Contrôler le véhicule",
"config.superbwarfare.client.vehicle.invert_aircraft_control": "Inverser le contrôle de l'aéronef",
"config.superbwarfare.client.vehicle.left_click_reload.des": "Définir sur VRAI pour inverser le contrôle de l'aéronef",
"config.superbwarfare.client.control": "Contrôler le véhicule",
"config.superbwarfare.client.control.invert_aircraft_control": "Inverser le contrôle de l'aéronef",
"config.superbwarfare.client.control.invert_aircraft_control.des": "Définir sur VRAI pour inverser le contrôle de l'aéronef",
"config.superbwarfare.common.gameplay": "Configuration du gameplay",
"config.superbwarfare.common.gameplay.respawn_reload": "Rechargement après réapparition",

View file

@ -542,9 +542,9 @@
"config.superbwarfare.client.display.armor_plate_hud.des": "オンにすると、胸部アーマーに装備されている防弾インサートの耐久性を左下隅に表示します",
"config.superbwarfare.client.display.stamina_hud": "スタミナHUD",
"config.superbwarfare.client.display.stamina_hud.des": "タクティカルスプリントや息止めの際にスタミナHUDを表示する",
"config.superbwarfare.client.vehicle": "車両制御",
"config.superbwarfare.client.vehicle.invert_aircraft_control": "航空機制御の反転",
"config.superbwarfare.client.vehicle.left_click_reload.des": "航空機の制御を反転するにはTRUEを設定します",
"config.superbwarfare.client.control": "車両制御",
"config.superbwarfare.client.control.invert_aircraft_control": "航空機制御の反転",
"config.superbwarfare.client.control.invert_aircraft_control.des": "航空機の制御を反転するにはTRUEを設定します",
"config.superbwarfare.common.gameplay": "ゲームプレイ設定",
"config.superbwarfare.common.gameplay.respawn_reload": "リスポーンリロード",

View file

@ -492,9 +492,9 @@
"config.superbwarfare.client.display.camera_rotate.des": "Немного трясёт экран при использовании оружия в руках",
"config.superbwarfare.client.display.armor_plate_hud": "HUD бронепластины",
"config.superbwarfare.client.display.armor_plate_hud.des": "Если включено, полоска прочности бронежилета надетого в слот нагрудника появится в нижнем левом углу",
"config.superbwarfare.client.vehicle": "Управление транспортом",
"config.superbwarfare.client.vehicle.invert_aircraft_control": "Инвертировать управление воздушным транспортом",
"config.superbwarfare.client.vehicle.left_click_reload.des": "Если включено, управление воздушным транспортом инвертировано",
"config.superbwarfare.client.control": "Управление транспортом",
"config.superbwarfare.client.control.invert_aircraft_control": "Инвертировать управление воздушным транспортом",
"config.superbwarfare.client.control.invert_aircraft_control.des": "Если включено, управление воздушным транспортом инвертировано",
"config.superbwarfare.common.gameplay": "Настройки геймплея",
"config.superbwarfare.common.gameplay.respawn_reload": "Перезарядка при возрождении",
"config.superbwarfare.common.gameplay.respawn_reload.des": "Перезаряжает все оружие в инвентаре после возрождения автоматически",

View file

@ -627,9 +627,11 @@
"config.superbwarfare.client.display.weapon_hud_y_offset.des": "武器HUD位置的竖直方向偏移量",
"config.superbwarfare.client.display.vehicle_info": "载具信息显示",
"config.superbwarfare.client.display.vehicle_info.des": "是否在看向载具的时候,显示该载具的信息",
"config.superbwarfare.client.vehicle": "载具控制",
"config.superbwarfare.client.vehicle.invert_aircraft_control": "飞行器鼠标反转",
"config.superbwarfare.client.vehicle.left_click_reload.des": "开启飞行器鼠标反转",
"config.superbwarfare.client.control": "控制配置",
"config.superbwarfare.client.control.invert_aircraft_control": "飞行器鼠标反转",
"config.superbwarfare.client.control.invert_aircraft_control.des": "开启飞行器鼠标反转",
"config.superbwarfare.client.control.mouse_sensitivity": "鼠标灵敏度",
"config.superbwarfare.client.control.mouse_sensitivity.des": "调整持枪时的鼠标灵敏度",
"config.superbwarfare.common.gameplay": "游戏内容配置",
"config.superbwarfare.common.gameplay.respawn_reload": "重生换弹",

View file

@ -1,10 +0,0 @@
{
"replace": false,
"values": [
"superbwarfare:projectile_boom",
"superbwarfare:custom_explosion",
"superbwarfare:laser",
"superbwarfare:laser_headshot",
"superbwarfare:laser_static"
]
}

View file

@ -0,0 +1,14 @@
{
"ItemID": "superbwarfare:medium_aerial_bomb",
"EntityID": "superbwarfare:mk_82",
"Offset": [
0,
-0.1,
0
],
"Scale": [
0.4,
0.4,
0.4
]
}

View file

@ -0,0 +1,12 @@
{
"ItemID": "superbwarfare:c4_bomb",
"EntityID": "superbwarfare:c4",
"HitDamage": 150,
"ExplosionDamage": 300,
"ExplosionRadius": 10,
"Offset": [
0,
-0.1,
0
]
}

View file

@ -0,0 +1,12 @@
{
"ItemID": "superbwarfare:rocket",
"EntityID": "superbwarfare:rpg_rocket",
"HitDamage": 270,
"ExplosionDamage": 130,
"ExplosionRadius": 10,
"Offset": [
0,
-0.03,
-1.8
]
}