完善客户端功能并同步差距文档
This commit is contained in:
+92
-4
@@ -3,6 +3,7 @@
|
||||
extends SceneTree
|
||||
|
||||
const Mse = preload("res://fx/mse.gd")
|
||||
const Mde = preload("res://fx/mde.gd")
|
||||
const EffectPlayer = preload("res://fx/effect_player.gd")
|
||||
const EffectRegistry = preload("res://fx/effect_registry.gd")
|
||||
|
||||
@@ -22,6 +23,7 @@ Group Particle
|
||||
MaxEmissionCount 5
|
||||
CycleLength 0.400000
|
||||
CycleLoopEnable 1
|
||||
LoopCount 2
|
||||
EmitterShape 3
|
||||
EmittingRadius 10.000000
|
||||
List TimeEventLifeTime
|
||||
@@ -58,8 +60,38 @@ Group Particle
|
||||
Group Particle
|
||||
{
|
||||
StartTime 0.200000
|
||||
Group EmitterProperty { MaxEmissionCount 10 EmitterShape 0 }
|
||||
Group ParticleProperty { SrcBlendType 5 DestBlendType 4 BillboardType 4 }
|
||||
Group EmitterProperty
|
||||
{
|
||||
MaxEmissionCount 10
|
||||
EmitterShape 3
|
||||
EmittingRadius 20.0
|
||||
EmitterAdvancedType 1
|
||||
EmitterEmitFromEdgeFlag 1
|
||||
}
|
||||
Group ParticleProperty
|
||||
{
|
||||
SrcBlendType 5
|
||||
DestBlendType 4
|
||||
BillboardType 4
|
||||
}
|
||||
}
|
||||
Group Light
|
||||
{
|
||||
StartTime 0.100000
|
||||
Duration 0.500000
|
||||
LoopFlag 0
|
||||
LoopCount 0
|
||||
MaxRange 300.000000
|
||||
AmbientColor 0.100000 0.200000 0.300000 1.000000
|
||||
DiffuseColor 0.800000 0.400000 0.100000 1.000000
|
||||
Attenuation0 0.000000
|
||||
Attenuation1 0.100000
|
||||
Attenuation2 0.000000
|
||||
List TimeEventRange
|
||||
{
|
||||
0.000000 0.000000
|
||||
0.500000 1.000000
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
@@ -72,6 +104,7 @@ func _ck(c: bool, m: String) -> void:
|
||||
func _init() -> void:
|
||||
_test_parser()
|
||||
_test_builder()
|
||||
_test_mde()
|
||||
_test_registry()
|
||||
if _fail == 0:
|
||||
print("PASS: fx_test (.mse parser + EffectPlayer + registry)")
|
||||
@@ -97,6 +130,8 @@ func _test_parser() -> void:
|
||||
var tex = p0.particle.get("TextureFiles")
|
||||
_ck(tex is Array and tex.size() == 1 and String(tex[0][0]) == "bottom_under.dds", "p0 TextureFiles")
|
||||
_ck(abs(float(s.particles[1].start_time) - 0.2) < 0.01, "p1 start_time 0.2")
|
||||
_ck(s.lights.size() == 1, "1 SimpleLight group")
|
||||
_ck(abs(float(s.lights[0].duration) - 0.5) < 0.01 and s.lights[0].range.size() == 2, "light duration and range curve")
|
||||
|
||||
func _test_builder() -> void:
|
||||
var m := Mse.new()
|
||||
@@ -107,14 +142,41 @@ func _test_builder() -> void:
|
||||
_ck(fx._emitters.size() == 2, "EffectPlayer built 2 GPUParticles3D")
|
||||
var g0: GPUParticles3D = fx._emitters[0]
|
||||
_ck(g0.amount == 5, "emitter 0 amount = 5")
|
||||
_ck(abs(float(g0.get_meta("cycle_length", 0.0)) - 0.4) < 0.001, "emitter 0 cycle length = 0.4")
|
||||
_ck(bool(g0.get_meta("cycle_loop", false)), "emitter 0 cycle loop enabled")
|
||||
_ck(int(g0.get_meta("loop_count", 0)) == 2, "emitter 0 loop count = 2")
|
||||
_ck(abs(g0.lifetime - 0.07732) < 0.01, "particle lifetime is not replaced by cycle length")
|
||||
_ck(g0.process_material is ParticleProcessMaterial, "emitter 0 has process material")
|
||||
var pm: ParticleProcessMaterial = g0.process_material
|
||||
_ck(pm.emission_shape == ParticleProcessMaterial.EMISSION_SHAPE_SPHERE, "emitter 0 sphere emission (shape 3)")
|
||||
_ck(g0.material_override is StandardMaterial3D, "emitter 0 draw material")
|
||||
_ck((g0.material_override as StandardMaterial3D).blend_mode == BaseMaterial3D.BLEND_MODE_ADD, "src5/dst2 -> additive blend")
|
||||
_ck(float(fx._emitters[1].get_meta("start_time")) == 0.2, "emitter 1 start_time meta = 0.2")
|
||||
_ck(bool(fx._emitters[1].get_meta("emitter_emit_from_edge", false)), "emitter 1 edge emission metadata")
|
||||
_ck(int(fx._emitters[1].get_meta("emitter_advanced_type", -1)) == 1, "emitter 1 advanced type metadata")
|
||||
var pm1: ParticleProcessMaterial = fx._emitters[1].process_material
|
||||
_ck(pm1.emission_shape == ParticleProcessMaterial.EMISSION_SHAPE_SPHERE_SURFACE,
|
||||
"emitter 1 edge sphere uses surface emission")
|
||||
_ck(abs(pm1.spread - 180.0) < 0.01, "OUTER emitter uses radial-velocity fallback spread")
|
||||
_ck(fx._lights.size() == 1, "EffectPlayer built 1 OmniLight3D")
|
||||
fx._process(0.11)
|
||||
_ck(fx._lights[0].visible, "SimpleLight becomes visible after start time")
|
||||
_ck(abs(fx._lights[0].omni_range - 0.06) < 0.02, "SimpleLight range follows TimeEventRange")
|
||||
var moving_rows: Array = [
|
||||
[0.0, "MOVING_TYPE_DIRECT", 0.0, 0.0, 0.0],
|
||||
[1.0, "MOVING_TYPE_BEZIER_CURVE", 100.0, 0.0, 0.0, 0.0, 100.0, 0.0],
|
||||
[2.0, "MOVING_TYPE_DIRECT", 200.0, 0.0, 0.0],
|
||||
]
|
||||
var direct_mid: Vector3 = fx._position_at(moving_rows, 0.5)
|
||||
var bezier_mid: Vector3 = fx._position_at(moving_rows, 1.5)
|
||||
_ck(abs(direct_mid.x - 0.5) < 0.001 and abs(direct_mid.y) < 0.001,
|
||||
"MOVING_TYPE_DIRECT interpolates in metres")
|
||||
_ck(abs(bezier_mid.x - 1.25) < 0.001 and abs(bezier_mid.y - 0.5) < 0.001,
|
||||
"MOVING_TYPE_BEZIER_CURVE uses previous control point")
|
||||
fx.play()
|
||||
_ck(g0.emitting, "emitter 0 emitting after play() (start_time 0)")
|
||||
fx._process(0.81)
|
||||
_ck(not g0.emitting, "finite particle cycle stops after LoopCount cycles")
|
||||
fx.queue_free()
|
||||
|
||||
func _test_registry() -> void:
|
||||
@@ -130,9 +192,35 @@ func _test_registry() -> void:
|
||||
p = fxr.resolve("geompung_3_sword")
|
||||
_ck(p != "" and FileAccess.file_exists(p), "registry resolved a real .mse (%s)" % p)
|
||||
if p != "":
|
||||
var s := fxr.spec_for("PC/ymir work/pc/warrior/effect/geompung_3_sword.mse")
|
||||
var s := fxr.spec_for("PC/ymir work/pc/warrior/effect/geompung.mse")
|
||||
_ck(s.get("particles", []).size() > 0, "real .mse parsed to >=1 particle (%d)" % s.get("particles", []).size())
|
||||
var parent := Node3D.new()
|
||||
get_root().add_child(parent)
|
||||
var fx := fxr.spawn("PC/ymir work/pc/warrior/effect/geompung_3_sword.mse", parent, true)
|
||||
var fx := fxr.spawn("PC/ymir work/pc/warrior/effect/geompung.mse", parent, true)
|
||||
_ck(fx != null and fx.get_parent() == parent, "spawn attached EffectPlayer")
|
||||
_ck(fx._mesh_nodes.size() > 0, "spawn built real .mde mesh instead of placeholder")
|
||||
if fx._mesh_nodes.size() > 0:
|
||||
var mn: Node3D = fx._mesh_nodes[0]
|
||||
_ck(int(mn.get_meta("mde_version", 0)) == 1, "real geompung.mde uses EffectData v1")
|
||||
_ck(mn.get_child_count() > 0 and mn.get_child(0) is MeshInstance3D, "mde geometry is MeshInstance3D")
|
||||
|
||||
func _test_mde() -> void:
|
||||
var assets := AssetRoot.path()
|
||||
if not DirAccess.dir_exists_absolute(assets):
|
||||
print(" (skip mde: no assets)")
|
||||
return
|
||||
var path := assets.path_join("PC/ymir work/pc/warrior/effect/geompung.mde")
|
||||
if not FileAccess.file_exists(path):
|
||||
print(" (skip mde: fixture missing)")
|
||||
return
|
||||
var data := Mde.new()
|
||||
var mesh := data.parse_file(path)
|
||||
_ck(data.last_error == "", "mde parses EffectData v1 (%s)" % data.last_error)
|
||||
_ck(int(mesh.get("version", 0)) == 1, "mde version 1")
|
||||
_ck(int(mesh.get("geometry_count", 0)) == 3, "mde geometry count = 3")
|
||||
_ck(int(mesh.get("frame_count", 0)) == 2, "mde frame count = 2")
|
||||
var geometries: Array = mesh.get("geometries", [])
|
||||
_ck(geometries.size() == 3 and geometries[0].frames.size() == 2, "mde keeps every geometry frame")
|
||||
if geometries.size() > 0 and geometries[0].frames.size() > 0:
|
||||
var frame: Dictionary = geometries[0].frames[0]
|
||||
_ck(frame.vertices.size() == frame.uvs.size() and frame.vertices.size() > 0, "mde expands indexed vertices with UVs")
|
||||
|
||||
Reference in New Issue
Block a user